1 sychronized内置锁
多个线程同时访问同一个变量,会导致不可预料的结果
上述代码执行的结果均是 10000+
1.1 对象锁和类锁
对象锁:成员方法上 or 内部同步代码块
类锁:类的静态方法上
注:加锁的对象必须是同一个,否则毫无意义
2 volatile最轻量的通信/同步机制
不同线程对这个变量进行操作时的可见性(一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的)
volatile并不保证线程安全(例:volatile int count ... count++ 最终结果仍不可预测)
适用场景:一个线程写、多个线程读场景
3 等待通知机制
线程通信:
1 线程A通知线程B
2 线程B轮询线程A
等待通知机制是个很好的方法:
线程A调用o.wait();进入等待状态;线程B调用o.notify()或o.notifyAll()方法,线程A收到通知后从o.wait();方法处返回,继续执行
notify():通知一个在对象上等待的线程,使其从 wait 方法返回
notifyAll():通知所有等待在该对象上的线程
wait():调用该方法的线程进入 WAITING 状态
wait(long):超时等待 n 毫秒
3.1 等待和通知的标准范式
等待方遵循如下原则:
1 获取对象的锁
2 如果条件不满足,那么调用对象的 wait()方法,被通知后仍要检查条件
3 条件满足则执行对应的逻辑
通知方遵循如下原则:
1 获得对象的锁
2 改变条件
3 通知所有等待在对象上的线程
在调用 wait()、notify()系列方法之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用 wait()方法、notify()系列方法
notify和notifyAll应该用谁?
尽可能用 notifyall(),谨慎使用 notify(),因为 notify()只会唤醒一个线程
4 CompleteableFuture
Future仅能拿到一个结果;实际工作中是 1任务组合 2链式调用,引入CompleteableFuture
Asynsc 表示异步,而 supplyAsync 与 runAsync 不同在于,supplyAsync 异步返回一个结果,runAsync 是 void
第二个函数第二个参数表示是用我们自己创建的线程池,否则采用默认的ForkJoinPool.commonPool()作为它的线程池
获得结果的方法:
public T get()
public T get(long timeout, TimeUnit unit)
public T getNow(T valueIfAbsent)
public T join()
getNow 有点特殊,如果结果已经计算完则返回结果或者抛出异常,否则返回给定的 valueIfAbsent 值
join 返回计算的结果或者抛出一个 unchecked 异常(CompletionException),它和 get 对抛出的异常的处理有些细微的区别
关键入参是函数式接口 Function。它的入参是上一个阶段计算后的结果,返回值是经过转化后结果
关键入参是函数式接口 Consumer。它的入参是上一个阶段计算后的结果,没有返回值
对上一步的计算结果不关心,执行下一个操作,入参是一个 Runnable 的实例,表示上一步完成后执行的操作
...