系列文章目录
Java多线程【1】synchronized对象锁、内置锁使用
Java多线程【2】Java wait/notify的使用于同步模式保护性暂停
Java多线程【3】同步模式之保护性暂停案例 相亲问题
Java多线程【4】interrupt线程的打断机制、两阶段终止模式
Java多线程【5】异步模式之生产者消费者
Java多线程【6】LockSupport park/unpark原理和使用以及于wait/notify的区别
文章目录
前言
当线程调用sleep()、join()
方法的时候,线程会进入WAIT
状态,按照操作系统的视角线程处于BLOCK
状态。线程获取轻量级锁失败时进入锁膨胀,会为锁对象申请一个monitor对象(监视器、管程),monitor对象中有两个队列,EntryList(同步队列)、WaitSet(等待队列)。wait方法会使当前线程进入到WaitSet
队列。
一、wait、notify、notifyAll
1.1、同步阻塞的区别和wait方法的区别
- 线程获取锁失败,线程会进入monitor对象的EntryList队列中等待,直到锁被释放,EntryList中的线程会不公平的被CPU调度。
- 当线程获取锁之后,调用锁对象的wait方法,这时候会立马释放锁。当前线程不会进入EntryList,而是进入WaitSet等待队列。
1.2、notify方法
- 当前调用锁对象的notify时,会将锁对象的WaitSet队列中的线程随机拿出一个,移动到EntryList队列中
- 等待线程释放锁,EntryList里面的线程不公平的被CPU调度。
1.3、notifyAll方法
- 当前调用锁对象的notifyAll时,会将锁对象的WaitSet队列中的线程全部拿出,移动到EntryList队列中
- 等待线程释放锁,EntryList里面的线程不公平的被CPU调度。
二、同步模式之保护性暂停
2.1、保护性暂停和轮询等待(cas)的区别
保护性暂停可以理解为一个线程等待另一个线程的结果返回后开始执行操作。例如我要泡茶的前提是我需要去买茶叶,那么买茶叶线程执行完成,我买到了茶叶才能开始泡茶线程。类似用volatile的元素在线程做轮询判断也可实现效果
- 轮询等待的过程中会一直占用CPU时间片,导致资源浪费。
- 保护性暂停会让线程进入
BLOCK
状态(java中的WAITING
或者TIMED_WAITING
),从而让出CPU资源。
2.2、Guarded Suspension
有一个结果需要从一个线程传递到另外一个线程,让两个线程关联同一个GuardedObject。
GuardedObject guardedObject = new GuardedObject();
new Thread(new Runnable() {
@Override
public void run() {
Object o = guardedObject.get();
System.out.println(o);
}
},"线程1").start();
new Thread(new Runnable() {
@SneakyThrows
@Override
public void run() {
TimeUnit.SECONDS.sleep(2);
guardedObject.set("123123123");
}
},"线程2").start();
TimeUnit.SECONDS.sleep(10);
}
2.3、Guarded Suspension Time Out
@Slf4j
public class GuardedObject {
private Object response;
public Object getResponse() {
return response;
}
public void setResponse(Object response) {
this.response = response;
}
public Object get(Integer timout){
long startTime = System.currentTimeMillis();
long expenseTime = 0;
long waitTime = timout - expenseTime;
while (response == null){
if(expenseTime < waitTime){
synchronized (this){
log.info("等待线程返回数据...");
try {
this.wait(waitTime);
expenseTime = System.currentTimeMillis() -startTime ;
}catch (InterruptedException e){
e.printStackTrace();
}
}
}else {
break;
}
}
log.info("线程返回数据...");
log.info("经历时间..."+expenseTime);
return this.getResponse();
}
public void set(Object data){
this.setResponse(data);
synchronized (this){
this.notify();
}
}