并发编程demo记录demo26

Executor 执行某一任务,需要重写execute方法
ExecutorService submit
Callable(有返回值) 约等于Runnable(没有返回值)
Executors 工具类 工厂类
ThreadPool
Future

六种线程池
fixed cached single scheduled workstealing(forkjoin基础上) forkjoin

ThreadpoolExecutor(fixed cached single scheduled四种线程池的底层)

PStreamAPI

demo1

/*
 认识Executor
 是一个借口
 */
package bingfaDemo.bingfa.T26;
import java.util.concurrent.Executor;//执行器
public class T01_MyExecutor implements Executor{
	public static void main(String[] args) {
		new T01_MyExecutor().execute(()->System.out.println("hello executor"));
	}
	@Override
	public void execute(Runnable command) { //执行一项任务
		//new Thread(command).run(); //新起一个线程去调用这个方法
		command.run(); //方法调用
	}
}

demo2

/*
 认识ExecutorService,阅读API文档
 认识submit方法,扩展了execute方法,具有一个返回值
 */
package bingfaDemo.bingfa.T26;

public class T02_ExecutorService  {

}

demo3

/*

认识Callable,对Runnable进行了扩展

Runnable(重写run方法)与Callable(重写call方法)区别:
1. call()方法可以有返回值,run方法没有返回值。(最主要的区别)
2. call()方法中可以抛出异常,run方法中不可以。


当调用一个线程需要有返回值时用Callable,否则用Runnable。
*/
package bingfaDemo.bingfa.T26;

public class T03_Callable {

}

demo4

/*
 认识Executors(是一个类不是借口),操作Executor的一个工具类,
 */
package bingfaDemo.bingfa.T26;

public class T04_Executors {
	public static void main(String[] args) {
		//Executors
	}
}

demo5

/*
线程池的概念

*/
package bingfaDemo.bingfa.T26;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class T05_ThreadPool {
	public static void main(String[] args) throws InterruptedException {
		ExecutorService service = Executors.newFixedThreadPool(5);
		//FixedThreadPool固定个数的线程池

		//

		/*
		启了五个线程,但是现在还没有启动,需要的时候才启动
		五个线程六个任务,其中一个线程执行两个任务

		一个任务可以有一个线程指向,剩下一个任务由于没有可用的线程,排在线程池维护的任务队列
		(大多数用的BlockingQueue)里,线程池的好处在于线程执行完任务不会消失,只是空闲下来,
		当有新的任务来的时候,空闲的线程可以直接执行,不用新启动线程(线程可以重用,可以节省资源)
		(启动线程和关闭线程都需要消耗资源,操作系统由拥用户态转为内核态)

		*/



		//execute submit方法可以
		for (int i = 0; i < 6; i++) {
			service.execute(() -> {
				try {
					TimeUnit.MILLISECONDS.sleep(500);//500ms
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("当前线程名称");
				System.out.println(Thread.currentThread().getName());
			});
		}
		System.out.println("----------service");
		System.out.println(service);
		//java.util.concurrent.ThreadPoolExecutor@7cca494b[Running(状态), pool size(大小) = 5, active threads(活动线程数) = 5, queued tasks(队列里的任务个数) = 1, completed tasks(完成是任务数) = 0]
		
		service.shutdown();//等所有任务执行完正常关闭
		System.out.println("---------service.isTerminated()");//所有的任务是否都指执行完了
		System.out.println(service.isTerminated());//false
		System.out.println("----------service.isShutdown()");//关了并不代表任务执行完了,只是代表正在关闭的过程状态中
		System.out.println(service.isShutdown());//true
		System.out.println("----------service");
		System.out.println(service);
		//java.util.concurrent.ThreadPoolExecutor@7cca494b[Shutting down(正在关闭), pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]
		
		TimeUnit.SECONDS.sleep(5);//5s
		System.out.println("------------service.isTerminated()");
		System.out.println(service.isTerminated());//true
		System.out.println("------------service.isShutdown()");
		System.out.println(service.isShutdown());//true
		System.out.println("-------------service");
		System.out.println(service);
		//java.util.concurrent.ThreadPoolExecutor@7cca494b[Terminated(正常结束), pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 6]
	}
}

demo6

/*
 认识future
 future代表Callable里面的返回值
 未来的结果

 */
package bingfaDemo.bingfa.T26;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

public class T06_Future {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//Future包括FutureTask(与Runnable相比),FutureTask包装了一个任务
		FutureTask<Integer> task = new FutureTask<>(()->{//Integer代表返回值是int类型
			TimeUnit.MILLISECONDS.sleep(500);
			return 1000;//有返回值
		});//Callable类型,上面两行相当于call方法

		//上面的匿名类相当于new Callable () { Integer call();}
		
		new Thread(task).start();
		
		System.out.println("返回值"+task.get()); //get是阻塞方法,一直等待task的执行完成,得到返回值1000
		
		//*******************************
		ExecutorService service = Executors.newFixedThreadPool(5);//起了5个线程
		//扔了一个任务
		//submit()可以直接往里扔一个Callable,Callable指向完之后返回一个结果放在Future
		Future<Integer> f = service.submit(()->{
			TimeUnit.MILLISECONDS.sleep(500);
			return 1;
		});
		System.out.println(f.get());//1 get是阻塞方法,一直等待task的执行完成,得到返回值1
		System.out.println(f.isDone());//任务是否执行完 true
		//不执行System.out.println(f.get());直接执行System.out.println(f.isDone());得到的结果是false
		//因为主线程直接起来,任务没有执行完
		
	}
}

demo7

/*
 线程池的概念:线程池用来并行计算,计算方便
 nasa
 */
package bingfaDemo.bingfa.T26;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/*
计算1-2000000所有的质数
*/

public class T07_ParallelComputing {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//第一种方式 6946
		long start = System.currentTimeMillis();
		getPrime(1, 200000); 
		long end = System.currentTimeMillis();
		System.out.println(end - start);

		//第二种方式:线程池(线程个数至少等于cpu的核数) 2838
		final int cpuCoreNum = 4;
		
		ExecutorService service = Executors.newFixedThreadPool(cpuCoreNum);

		//为什么不平均分1-5 5-10 10-15 15-20,因为后面的数字大,计算的时间长
		MyTask t1 = new MyTask(1, 80000);
		MyTask t2 = new MyTask(80001, 130000);
		MyTask t3 = new MyTask(130001, 170000);
		MyTask t4 = new MyTask(170001, 200000);
		
		Future<List<Integer>> f1 = service.submit(t1);
		Future<List<Integer>> f2 = service.submit(t2);
		Future<List<Integer>> f3 = service.submit(t3);
		Future<List<Integer>> f4 = service.submit(t4);
		
		start = System.currentTimeMillis();
		f1.get();
		f2.get();
		f3.get();
		f4.get();
		end = System.currentTimeMillis();
		System.out.println(end - start);
	}
	
	static class MyTask implements Callable<List<Integer>> {
		int startPos, endPos;
		
		MyTask(int s, int e) {
			this.startPos = s;
			this.endPos = e;
		}
		
		@Override
		public List<Integer> call() throws Exception {
			List<Integer> r = getPrime(startPos, endPos);
			return r;
		}
		
	}

	//判断一个值是不是质数
	static boolean isPrime(int num) {
		for(int i=2; i<=num/2; i++) {
			if(num % i == 0) return false;
		}
		return true;
	}

	//start-end中所有的质数放入list中
	static List<Integer> getPrime(int start, int end) {
		List<Integer> results = new ArrayList<>();
		for(int i=start; i<=end; i++) {
			if(isPrime(i)) results.add(i);
		}
		
		return results;
	}
}

demo8

package bingfaDemo.bingfa.T26;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/*
缓存的线程池
刚开始没有线程,来一个任务启一个线程,再来一个任务,如果有线程空闲,就用空闲线程来执行,
否则新启动一个线程,能启动的线程数是本机能支撑的线程数(几万个,最大不能超过int类型的最大数,不是没有界限的线程池)

线程空闲超过1min(默认的生存周期),自动销毁
 */
public class T08_CachedPool {
	public static void main(String[] args) throws InterruptedException {
		ExecutorService service = Executors.newCachedThreadPool();
		System.out.println("服务"+service);
		//服务java.util.concurrent.ThreadPoolExecutor@677327b6[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
		//两个任务
		for (int i = 0; i < 2; i++) {
			service.execute(() -> {
				try {
					TimeUnit.MILLISECONDS.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("线程名"+Thread.currentThread().getName());
				//线程名pool-1-thread-1
				//线程名pool-1-thread-2
			});
		}
		System.out.println("服务"+service);
		//服务java.util.concurrent.ThreadPoolExecutor@677327b6[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 0]
		TimeUnit.SECONDS.sleep(80);//线程空闲超过1min(默认的生存周期),自动销毁
		System.out.println("服务"+service);
		//服务java.util.concurrent.ThreadPoolExecutor@677327b6[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 2]
	}
}

demo9

package bingfaDemo.bingfa.T26;
//线程是只有一个线程 保证任务顺序执行

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class T09_SingleThreadPool {
	public static void main(String[] args) {
		ExecutorService service = Executors.newSingleThreadExecutor();
		//线程是只有一个线程 保证任务顺序执行
		for(int i=0; i<5; i++) {
			final int j = i;
			service.execute(()->{
				
				System.out.println(j + " " + Thread.currentThread().getName());
			});
		}
			
	}
}

demo10

package bingfaDemo.bingfa.T26;

import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/*
执行定时的任务

线程池里面的线程可以重复使用
*/
public class T10_ScheduledPool {
	public static void main(String[] args) {
		ScheduledExecutorService service = Executors.newScheduledThreadPool(4);
		//计划中的定时任务
		service.scheduleAtFixedRate(()->{ //以固定的频率执行某一任务
			try {
				TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName());
		}, 0, 500, TimeUnit.MILLISECONDS);
		/*
		public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,//首次延迟执行的时间
                                                  long period,//每隔多长时间执行这个任务
                                                  TimeUnit unit);//时间单位
		*/
	}
}

demo11

/*
 原来是任务分配给线程,现在是线程指向完主动去找活干(去执行另一个线程维护的任务)
 */
package bingfaDemo.bingfa.T26;

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class T11_WorkStealingPool {
	public static void main(String[] args) throws IOException {
		//Executors.newWorkStealingPool()是由ForkJoinPool实现的
		ExecutorService service = Executors.newWorkStealingPool();//计算机是几核,启动几个线程
		System.out.println(Runtime.getRuntime().availableProcessors());//4核
		//五个任务
		service.execute(new R(1000));
		service.execute(new R(2000));
		service.execute(new R(2000));
		service.execute(new R(2000)); //daemon
		service.execute(new R(2000));
		/*
		1000 ForkJoinPool-1-worker-1
		2000 ForkJoinPool-1-worker-2
		2000 ForkJoinPool-1-worker-3
		2000 ForkJoinPool-1-worker-0
		2000 ForkJoinPool-1-worker-1

		第一个执行的线程(1)先指向完,所以第五个任务是第一个线程(1)来执行。
		 */
		//由于线程池里产生的所有的线程都是精灵线程(守护线程、后台线程),主线程不阻塞的话,看不到输出
		//精灵线程在后台不停的运行,只要虚拟机不退出,就不退出,不断运行,有任务来一定会主动去拿
		//精灵线程又叫守护线程,又叫后台线程
		System.in.read(); //主函数阻塞(如果注释掉这句话,只输出4)
	}

	static class R implements Runnable {
		int time;
		R(int t) {
			this.time = t;
		}
		@Override
		public void run() {
			try {
				TimeUnit.MILLISECONDS.sleep(time);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(time  + " " + Thread.currentThread().getName());
		}
	}
}

demo12

package bingfaDemo.bingfa.T26;

import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;

/*
Fork分叉Join合并

难以完成的大任务,时间特别长

大任务分成子任务,子任务可以再分,最后合并起来

任务分割,结果合并

ForkJoinPool里面是ForkJoinTake,可以对任务进行自动的切分,


*/
public class T12_ForkJoinPool {
	static int[] nums = new int[1000000];
	static final int MAX_NUM = 50000;//每一个任务不超过计算50000个数字的和
	static Random r = new Random();
	
	static {
		for(int i=0; i<nums.length; i++) {
			nums[i] = r.nextInt(100);//每一个数字都是100以内的
		}
		System.out.println(Arrays.stream(nums).sum()); //stream api //最普通是for循环
	}
	

	static class AddTask extends RecursiveAction {//RecursiveAction没有返回值
		int start, end;//起始位置,结束位置
		AddTask(int s, int e) {
			start = s;
			end = e;
		}
		@Override
		protected void compute() {
			if(end-start <= MAX_NUM) {//长度小于 MAX_NUM(50000),直接进行计算
				long sum = 0L;
				for(int i=start; i<end; i++) sum += nums[i];
				System.out.println("from:" + start + " to:" + end + " = " + sum);
			} else {
				//超过MAX_NUM再进行切分
				int middle = start + (end-start)/2;
				AddTask subTask1 = new AddTask(start, middle);
				AddTask subTask2 = new AddTask(middle, end);
				subTask1.fork();//fork()一定有新的线程启动
				subTask2.fork();
			}
			
			
		}
		
	}

	

	public static void main(String[] args) throws IOException {
		ForkJoinPool fjp = new ForkJoinPool();
		AddTask task = new AddTask(0, nums.length);
		fjp.execute(task);
		System.in.read();
		
	}
}

demo12_2

package bingfaDemo.bingfa.T26;

import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/*
应用场景:大规模任务计算

Fork分叉Join合并

难以完成的大任务,时间特别长

大任务分成子任务,子任务可以再分,最后合并起来

任务分割,结果合并

ForkJoinPool里面是ForkJoinTake,可以对任务进行自动的切分,


*/
public class T12_ForkJoinPool2 {
	static int[] nums = new int[1000000];
	static final int MAX_NUM = 50000;//每一个任务不超过计算50000个数字的和
	static Random r = new Random();
	
	static {
		for(int i=0; i<nums.length; i++) {
			nums[i] = r.nextInt(100);//每一个数字都是100以内的
		}
		System.out.println(Arrays.stream(nums).sum()); //stream api //最普通是for循环
	}
	


	static class AddTask extends RecursiveTask<Long> {//RecursiveTask有返回值,可以对这些分段计算的结果进行汇总
		private static final long serialVersionUID = 1L;
		int start, end;//起始位置,结束位置
		AddTask(int s, int e) {
			start = s;
			end = e;
		}
		@Override
		protected Long compute() {
			if(end-start <= MAX_NUM) {//长度小于 MAX_NUM(50000),直接进行计算
				long sum = 0L;
				for(int i=start; i<end; i++) sum += nums[i];
				return sum;
			}
			//超过MAX_NUM再进行切分
			int middle = start + (end-start)/2;
			AddTask subTask1 = new AddTask(start, middle);
			AddTask subTask2 = new AddTask(middle, end);
			subTask1.fork();//fork()一定有新的线程启动
			subTask2.fork();
			return subTask1.join() + subTask2.join();
		}
	}
	
	public static void main(String[] args) throws IOException {
		ForkJoinPool fjp = new ForkJoinPool();
		AddTask task = new AddTask(0, nums.length);
		fjp.execute(task);
		long result = task.join();//join本身是阻塞的
		System.out.println(result);
	}
}

demo13

/**
 * 自定义线程池
 */
package bingfaDemo.bingfa.T26;


public class T13_ThreadPoolExecutor {
	public static void main(String[] args) {
		
	}
}

demo14

package bingfaDemo.bingfa.T26;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class T14_ParallelStreamAPI {
	public static void main(String[] args) {
		List<Integer> nums = new ArrayList<>();
		Random r = new Random();
		//10000个数,范围在1000000-2000000之间
		for(int i=0; i<10000; i++)
			nums.add(1000000 + r.nextInt(1000000));
		
		//System.out.println(nums);
		
		long start = System.currentTimeMillis();
		nums.forEach(v->isPrime(v));//每个数是不是质数
		long end = System.currentTimeMillis();
		System.out.println("way1"+ (end - start));
		
		//使用parallel stream api
		
		start = System.currentTimeMillis();
		nums.parallelStream().forEach(T14_ParallelStreamAPI::isPrime);//parallelStream()默认使用多线程
		end = System.currentTimeMillis();
		
		System.out.println("way2"+(end - start));
	}
	
	static boolean isPrime(int num) {
		for(int i=2; i<=num/2; i++) {
			if(num % i == 0) return false;
		}
		return true;
	}
}
发布了172 篇原创文章 · 获赞 22 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_44135282/article/details/103544495
今日推荐