2019.7.21笔记——java并发线程相关

Executor

可以继承这个接口,通过实现execute这个方法,来开启线程完成任务。这个继承了executor的类就相当于任务管理器,可以调用这个类的execute方法来将任务交给这个类。

/**
 * 认识Executor
 * JDK8在线文档地址:https://docs.oracle.com/javase/8/docs/api/index.html
 */
public class Demo1_Executor implements Executor{

	public static void main(String[] args) {
		Demo1_Executor executor = new Demo1_Executor();
		executor.execute(()->{
			try {
				System.out.println("线程开始");
				TimeUnit.MILLISECONDS.sleep(500);
				System.out.println("线程结束");
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		});
	}
	public void execute(Runnable command) {
		command.run();
	}
}

结果

任务开始
任务结束

关于偏向锁的具体介绍

Executorservice

用来管理Executor接口相关的线程池,可以接收其他线程池创建出来的对象。

FutureTask中的Callable和Future

FutureTask可以创建一个有返回值且可以抛异常的任务

Callable对Runnable进行了扩展,Runnable由于重写了,不能抛出异常,但是Callable可以有返回值,也可以抛出异常

Future则是任务的返回值

public class Demo6_Future {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		FutureTask<Integer> task = new FutureTask<>(()->{//new callable
			TimeUnit.MILLISECONDS.sleep(500);
			return 1000;
		});
		
		new Thread(task).start();
		
		System.out.println(task.get());
		
		ExecutorService service = Executors.newFixedThreadPool(5);
		Future<Integer> f = service.submit(()->{
			TimeUnit.MILLISECONDS.sleep(500);
			return 1;
		});
		System.out.println(f.get());
		System.out.println(f.isDone());
	}
}

需要注意的是在调用get方法取返回值的时候主线程的被阻塞的

结果

1000
1
true

executors

executor的工具类,可以创建许多线程池

newFixedThreadPool

可以设置线程池大小,队列式的线程池

Executorservice的shutdown方法会关闭线程池,但线程池的线程还是会执行完,并回收线程

shutdownNow方法会关闭线程并且直接停止线程

/**
 * 线程池的概念
 */
public class Demo5_ThreadPool {

	public static void main(String[] args) throws InterruptedException {
		ExecutorService service = Executors.newFixedThreadPool(5);
		for (int i = 0; i < 6; i++) {
			service.execute(()->{
				try {
					TimeUnit.MICROSECONDS.sleep(500);
				} catch (Exception e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName());
			});
		}
		
		System.out.println(service);
		
		service.shutdown();
		System.out.println(service.isTerminated());
		System.out.println(service.isShutdown());
		System.out.println(service);
		
		TimeUnit.SECONDS.sleep(5);
		System.out.println(service.isTerminated());
		System.out.println(service.isShutdown());
		System.out.println(service);
	}
}

结果

java.util.concurrent.ThreadPoolExecutor@58372a00[Running, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]
false
true
java.util.concurrent.ThreadPoolExecutor@58372a00[Shutting down, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]
pool-1-thread-1
pool-1-thread-2
pool-1-thread-4
pool-1-thread-3
pool-1-thread-5
pool-1-thread-1
true
true
java.util.concurrent.ThreadPoolExecutor@58372a00[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 6]

如果把shutdown方法换成shutdownNow,那么就会抛异常,因为直接中断了所有线程

java.util.concurrent.ThreadPoolExecutor@58372a00[Running, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]
false
true
java.util.concurrent.ThreadPoolExecutor@58372a00[Shutting down, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0]
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:340)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
	at com.luban.demo1.Demo5_ThreadPool.lambda$main$0(Demo5_ThreadPool.java:18)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
pool-1-thread-3
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:340)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
	at com.luban.demo1.Demo5_ThreadPool.lambda$main$0(Demo5_ThreadPool.java:18)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
pool-1-thread-2
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:340)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
	at com.luban.demo1.Demo5_ThreadPool.lambda$main$0(Demo5_ThreadPool.java:18)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
java.lang.InterruptedException: sleep interrupted
pool-1-thread-1
	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:340)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
	at com.luban.demo1.Demo5_ThreadPool.lambda$main$0(Demo5_ThreadPool.java:18)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
pool-1-thread-5
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at java.lang.Thread.sleep(Thread.java:340)
	at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386)
	at com.luban.demo1.Demo5_ThreadPool.lambda$main$0(Demo5_ThreadPool.java:18)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)
pool-1-thread-4
true
true
java.util.concurrent.ThreadPoolExecutor@58372a00[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 5]

需要注意的是这种线程池只有关闭了才会回收线程

newCachedThreadPool

缓存式的线程池,来一个任务创建一个线程,空闲的线程就接上,每个线程到了一定时间会回收,每个线程都有各自的存活时间

public class Demo8_CachedPool {

	public static void main(String[] args) throws InterruptedException {
		ExecutorService service = Executors.newCachedThreadPool();
		System.out.println(service);
		
		for (int i = 0; i < 2; i++) {
			service.execute(()->{
				try {
					TimeUnit.MILLISECONDS.sleep(500);
				} catch (Exception e) {
					e.printStackTrace();
				}
				System.out.println(Thread.currentThread().getName());
			});
		}
		
		System.out.println(service);
		
		TimeUnit.SECONDS.sleep(60);
		System.out.println(service);

		TimeUnit.SECONDS.sleep(1);
		System.out.println(service);
	}
}

这种线程池的线程上限为integer的最大值,而且默认为最大值
结果

java.util.concurrent.ThreadPoolExecutor@7f31245a[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@7f31245a[Running, pool size = 2, active threads = 2, queued tasks = 0, completed tasks = 0]
pool-1-thread-2
pool-1-thread-1
java.util.concurrent.ThreadPoolExecutor@7f31245a[Running, pool size = 2, active threads = 0, queued tasks = 0, completed tasks = 2]
java.util.concurrent.ThreadPoolExecutor@7f31245a[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 2]

可以看到因为来了两个任务所以启动了两个线程

newSingleThreadExecutor

每次只有一个任务会执行,一个一个执行

public class Demo9_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());
			});
		}
	}
}

结果

0 pool-1-thread-1
1 pool-1-thread-1
2 pool-1-thread-1
3 pool-1-thread-1
4 pool-1-thread-1

可以看到任务是一个一个完成的

newScheduledThreadPool

可以设置任务开始执行时间,循环执行的间隔时间

public class Demo10_ScheduledPool {

	public static void main(String[] args) {
		ScheduledExecutorService service = Executors.newScheduledThreadPool(4);
		
		service.scheduleAtFixedRate(()->{
			try {
				TimeUnit.MILLISECONDS.sleep(1000);
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName());
		}, 0, 500, TimeUnit.MILLISECONDS);
	}
}

结果

pool-1-thread-1
pool-1-thread-1
pool-1-thread-2
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
pool-1-thread-1
............循环执行,不会停止

这个方法的第一个参数是Runnable接口,第二个参数是开始的时间,第二个是循环执行的间隔时间,第四个参数是时间单位

scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) 

newWorkStealingPool

这线程池里面的线程是守护线程,同时这里面的线程如果在执行完自己的任务后会直接从别的线程的任务队列里偷取任务

public class Demo11_WorkStealingPool {
	public static void main(String[] args) throws InterruptedException {
		ExecutorService service = Executors.newWorkStealingPool();
		System.out.println(Runtime.getRuntime().availableProcessors());
		
		service.execute(new R(1000));
		service.execute(new R(2000));
		service.execute(new R(2000));
		service.execute(new R(2000));
		service.execute(new R(2000));
		service.execute(new R(2000));
		service.execute(new R(2000));
		service.execute(new R(2000));
		service.execute(new R(2000));

		TimeUnit.SECONDS.sleep(10);
	}
	
	static class R implements Runnable{
		int time;
		public 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());
		}
	}
}

结果

8
1000 ForkJoinPool-1-worker-1
2000 ForkJoinPool-1-worker-6
2000 ForkJoinPool-1-worker-0
2000 ForkJoinPool-1-worker-2
2000 ForkJoinPool-1-worker-5
2000 ForkJoinPool-1-worker-3
2000 ForkJoinPool-1-worker-4
2000 ForkJoinPool-1-worker-7
2000 ForkJoinPool-1-worker-1

因为里面的线程都是守护线程所以当主线程的睡眠时间更短时会有不一样的现象,现在把时间设为1秒

8
1000 ForkJoinPool-1-worker-1

可以看到只有第一个线程执行完了任务,因为主线程结束了,守护线程也会跟着结束

ForkJoinPool

通过fork和join方法实现任务的切分

public class Demo12_ForkJoinPool {
	static int[] nums = new int[1000000];
	static final int MAX_NUM = 50000;
	static Random r = new Random();

	static {
		for(int i=0; i<nums.length; i++) {
			nums[i] = r.nextInt(100);
		}
		System.out.println(Arrays.stream(nums).sum());
	}
	
	/*static class AddTask extends RecursiveAction {
		
		int start, end;
		
		AddTask(int s, int e) {
			start = s;
			end = e;
		}

		@Override
		protected void compute() {
			if(end-start <= MAX_NUM) {
				long sum = 0L;
				for(int i=start; i<end; i++){
					sum += nums[i];
				}
				System.out.println(sum);
			} else {
				int middle = start + (end-start)/2;
				AddTask subTask1 = new AddTask(start, middle);
				AddTask subTask2 = new AddTask(middle, end);
				subTask1.fork();
				subTask2.fork();
			}
		}
	}*/

	static class AddTask extends RecursiveTask<Long> {

		int start, end;
		
		AddTask(int s, int e) {
			start = s;
			end = e;
		}

		@Override
		protected Long compute() {
			if(end-start <= MAX_NUM) {
				long sum = 0L;
				for(int i=start; i<end; i++){
					sum += nums[i];
				}
				return sum;
			} 
			int middle = start + (end-start)/2;
			AddTask subTask1 = new AddTask(start, middle);
			AddTask subTask2 = new AddTask(middle, end);
			subTask1.fork();
			subTask2.fork();
			return subTask1.join() + subTask2.join();
		}
	}
	
	public static void main(String[] args) {
		ForkJoinPool forkJoinPool = new ForkJoinPool();
		AddTask task = new AddTask(0, nums.length);
		forkJoinPool.execute(task);
		long result = task.join();
		System.out.println(result);

		try {
			TimeUnit.SECONDS.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}

结果

49513285
49513285

想要使用这个线程池必须要有继承RecursiveTask类的对象,同时要把执行的任务重写在compute方法中,在方法中,通过fork来分配子任务,join方法得到子任务的返回值

ThreadPoolExecutor

通过调用ThreadPoolExecutor可以自定义线程池

下面是它的构造器

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) 
创建具有给定的初始参数和默认线厂和拒绝执行处理程序的一个新的 ThreadPoolExecutor。  

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) 
创建具有给定的初始参数和默认线厂一个新的 ThreadPoolExecutor。 
 
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) 
创建一个新的 ThreadPoolExecutor与给定的初始参数和默认拒绝执行处理程序。  

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) 
创建具有给定的初始参数的一种新 ThreadPoolExecutor。  

我们可以通过返回一个ThreadPoolExecutor,其中的参数可以自定义,这样同样也可以创建一个线程池

这里只对第一个做解释

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) 

corePoolSize是核心线程多少
maximumPoolSize是最大线程数
keepAliveTime是除核心线程之外的线程最大空闲时间
unit是时间单位
workQueue是每个线程的任务队列类型

execute()的逻辑应该是:

  1. 如果当前运行的线程,少于corePoolSize,则创建一个新的线程来执行任务。
  2. 如果运行的线程等于或多于 corePoolSize,将任务加入 BlockingQueue。
  3. 如果加入 BlockingQueue 成功,需要二次检查线程池的状态如果线程池没有处于Running,则从 BlockingQueue 移除任务,启动拒绝策略。
  4. 如果线程池处于 Running状态,则检查工作线程(worker)是否为0。如果为0,则创建新的线程来处理任务。如果启动线程数大于maximumPoolSize,任务将被拒绝策略拒绝。
  5. 如果加入 BlockingQueue 。失败,则创建新的线程来处理任务。
  6. 如果启动线程数大于maximumPoolSize,任务将被拒绝策略拒绝。

线程池 execute() 的工作逻辑

线程池简要模型

在这里插入图片描述

线程池的线程的多少最优一般是cpu的核心数加一

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值