目录
多线程
两个线程,一个输出字母,一个输出数字,交替输出
方式一: LockSupport.unpark(Thread1) 与 LockSupport.park()
方式二:定义一个volatile的变r,自旋锁
方式三:两个阻塞队列capacity=1,先从队列里面取值,取到值就输出,取不到就阻塞等待
方式四:synchronize、wait、notify
注意遍历输出完之后要notify对方,否则对方会一直wait
方式五:lock.new两个condition,T1在condition1上等待,输出后通知condition2,T2在condition2上等待,输出后通知condition1
volatile
- 只要对volatile修饰的域产生写操作,所有的读操作都会看到这个修改,因为volatile域会被立即写入主存,而读操作就发生在主存中
- 如果多个任务同时访问某个域,那么这个域就应该是volatile的,否则就应该同步来访问
- 一个任务的任何写入操作对这个任务来说都是可视的,所以不需要volatile
线程与任务
- 我们对线程没有任何实际控制权
- 将任务附着在线程上,以使得线程驱动任务
正确使用线程池
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor();
// 核心线程数
poolTaskExecutor.setCorePoolSize(10);
// 线程池维护线程的最大数量,只有在缓冲队列满了之后才会申请超过核心线程数的线程
poolTaskExecutor.setMaxPoolSize(100);
// 缓存队列
poolTaskExecutor.setQueueCapacity(50);
// 核心线程之外的线程在空闲时间到达之后会被销毁
poolTaskExecutor.setKeepAliveSeconds(200);
// 异步方法内部线程名称
poolTaskExecutor.setThreadNamePrefix("myThread-");
// n当然不是只有CallerRunsPolicy一种可选
poolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
poolTaskExecutor.initialize();
return poolTaskExecutor;
}
ThreadPoolExocutor 是一个executor
ThreadPoolTaskExecutor 是一个executor,还有定时调度功能
ExecutorService也是一个executor,
ScheduledExecutorService还是一个executor
newFixedThreadPool(),newCachedThreadPool() 等几个方法,
实际上也是间接调用了ThreadPoolExocutor ,不过是传的不同的构造参数
Executor与线程池
- CachedThreadPool与FixThreadPool和SingleThreadExecutor差异
CachedThreadPool会创建与所需数量相同的线程
FixThreadPool会创建指定数量的线程
SingleThreadExecutor相当于FixThreadPool参数为1 - 任何线程池中,现有线程在可能情况下,都会被自动复用
Runnable task1 = new Runnable() {
@Override
public void run() {
while (true) {
System.out.println("111");
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
ExecutorService executorService = Executors.newFixedThreadPool(1);
ExecutorService executorService1 = Executors.newSingleThreadExecutor();
executorService.execute(task1);
从任务中产生返回值
class TaskWithResult implements Callable<Integer> {
@Override
public Integer call() throws Exception {
return 1024;
}
}
ExecutorService executorService = Executors.newFixedThreadPool(1);
Future<Integer> submit = executorService.submit(new TaskWithResult());
// 阻塞直到等待结果返回
// V get(long timeout, TimeUnit unit)也可以指定等待时间
Integer integer = submit.get();
// 判断是否已经返回结果
boolean done = submit.isDone();
后台线程的finally一定会执行吗
不一定,非后台线程结束,后台线程也会结束,不会执行finally了
捕获异常
- 你不能捕获从线程逃逸的异常
- 异常不会从一个线程传播到另外一个线程
- 但是使用线程池,依然会抛出异常到控制台
try {
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.execute(exceptionTask);
}catch (Exception e) {
// 捕获无效,依然会在控制台打印异常
e.printStackTrace();
}
当线程池只有一个线程的时候
只会执行一个线程,而且会一直等这个线程执行完毕
static class Task1 implements Runnable{
private Object object;
public Task1(Object object) {
this.object = object;
}
@Override
public void run() {
synchronized (object) {
System.out.println("task1..begin");
try {
object.notifyAll();
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task1..end");
object.notifyAll();
}
}
}
static class Task2 implements Runnable{
private Object object;
public Task2(Object object) {
this.object = object;
}
@Override
public void run() {
synchronized (object) {
System.out.println("task2..begin");
try {
object.notifyAll();
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task2..end");
object.notifyAll();
}
}
}
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService.execute(new Task1(lock));
executorService.execute(new Task2(lock));
ReentrantLock,Condition
ReentrantLock lock = new ReentrantLock();
lock.lock();
finally {
lock.unlock();
}
lock.tryLock();
// 若锁被其他线程获取,等待两秒
lock.tryLock(2,TimeUnit.SECONDS);
Condition condition = lock.newCondition();
condition.signalAll();
condition.await();
// 让出锁两秒,然后继续竞争锁
condition.await(2,TimeUnit.SECONDS);
// java编程思想 704
1.一个任务是将蜡涂在汽车上,另外一个是抛光汽车,先涂蜡,再抛光,再涂蜡再抛光,重复10次
// java编程思想 709
2.饭店里面有1厨师和1服务员,服务员等待厨师准备好膳食,当厨师准备好,通知服务员取走膳食
BlockingQueue
- 任何时候,都只允许一个任务插入或移除元素
- 取元素时,若为空,阻塞等待
// java并发编程,715
1.一台机器具有三个任务,一台制作吐司,一台给吐司抹黄油,一台在抹过黄油的吐司涂果酱
CountDownLatch
- 设置一个初始计数值,调用await方法将阻塞,调用countDown()减少计数值,为0则放行
1.一个分析获得数据的任务,两个渲染数据到模板的任务,主线程返回静态页的任务。使用闭锁,控制最后返回静态页
2.先要分析得到数据,然后再开两个任务将数据渲染到两个模板,仅当一个模板渲染完成之后最后返回静态页
Semaphore
允许N个任务同时访问这项资源
Exchanger
用于两个任务交换对象,对象在创建的同时被消费
ScheduledExecutorService
定时任务还有quartz框架
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
// 延迟一秒启动,每隔两秒启动一次
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("ScheduledTask");
}
}, 1, 2, TimeUnit.SECONDS);
// 延迟一秒启动,执行一次
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
System.out.println("ScheduledTask");
}
},1, TimeUnit.SECONDS);