一、Wait/Notify
当线程执行任务的时候,发现条件不满足,则进行wait 条件满足后,再次进行任务执行
1. API
wait( ) notify( ) notifyAll( )
Object类的方法,必须成为锁的owner时候才能使用
public final void wait( ) throws InterruptedException
public final native void wait( long timeoutMillis) throws InterruptedException
public final native void notify( )
public final native void notifyAll( )
2. 原理
Owner线程发现条件不满足,调用wait,即进入WaitSet变为WAITING状态 wait会释放当前锁资源
1 . BLOCK和WAITING的线程都处于阻塞状态,不占用cpu
2 . BLOCK线程会在Owner线程释放锁时唤醒
3 . WAITING线程会在Owner线程调用notify时唤醒,但唤醒后只是进入EntryList重新竞争锁
3. 实现
package com. nike. erick. d02 ;
import java. util. concurrent. TimeUnit ;
public class Demo01 {
private static Object lock = new Object ( ) ;
public static void main ( String [ ] args) throws InterruptedException {
Thread firstThread = new Thread ( ( ) -> {
synchronized ( lock) {
try {
System . out. println ( "first thread coming" ) ;
lock. wait ( ) ;
System . out. println ( "first thread ending...." ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
}
} ) ;
Thread secondThread = new Thread ( ( ) -> {
synchronized ( lock) {
try {
System . out. println ( "second thread coming" ) ;
lock. wait ( ) ;
System . out. println ( "second thread ending...." ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
}
} ) ;
firstThread. start ( ) ;
secondThread. start ( ) ;
TimeUnit . SECONDS. sleep ( 2 ) ;
synchronized ( lock) {
lock. notifyAll ( ) ;
}
}
}
package com. nike. erick. d02 ;
public class Demo02 {
private static Object lock = new Object ( ) ;
public static void main ( String [ ] args) {
new Thread ( ( ) -> {
try {
lock. wait ( ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
} ) . start ( ) ;
}
}
4. Wait/Sleep
1 . Wait 是Object的方法 Sleep 是线程的静态方法
2 . Wait 必须和synchronized结合使用 Sleep 不需要
3 . Wait 会放弃当前线程的锁资源 Sleep 不会释放锁(如果工作时候带锁)
4 . 都会让出cpu资源,状态都是Timed-Waiting
二、Wait使用
防止虚假唤醒的问题,确保线程一定是执行完毕任务后才会结束
1. 单个线程wait
package com. nike. erick. d04 ;
import java. util. concurrent. TimeUnit ;
public class Demo01 {
private static final Object lock = new Object ( ) ;
private static boolean hasCigarette = false ;
public static void main ( String [ ] args) throws InterruptedException {
new Thread ( ( ) -> {
synchronized ( lock) {
while ( ! hasCigarette) {
try {
System . out. println ( "没烟,休息会儿" ) ;
lock. wait ( ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
}
System . out. println ( "烟来了,开始干活" ) ;
}
} ) . start ( ) ;
TimeUnit . SECONDS. sleep ( 5 ) ;
synchronized ( lock) {
lock. notify ( ) ;
hasCigarette = true ;
System . out. println ( "烟送到了" ) ;
}
}
}
2. 多个线程wait
java 11 中,谁先进入WaitSet, notify先唤醒谁
package com. nike. erick. d04 ;
import java. util. concurrent. TimeUnit ;
public class Demo02 {
private static final Object lock = new Object ( ) ;
private static boolean hasCigarette = false ;
private static boolean hasDinner = false ;
public static void main ( String [ ] args) throws InterruptedException {
new Thread ( ( ) -> {
synchronized ( lock) {
while ( ! hasCigarette) {
try {
System . out. println ( "烟没来,歇会儿" ) ;
lock. wait ( ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
}
System . out. println ( "烟来了,小男干活" ) ;
}
} ) . start ( ) ;
new Thread ( ( ) -> {
synchronized ( lock) {
while ( ! hasDinner) {
try {
System . out. println ( "外卖没来,歇会儿" ) ;
lock. wait ( ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
}
System . out. println ( "外卖来了,小女干活" ) ;
}
} ) . start ( ) ;
TimeUnit . SECONDS. sleep ( 2 ) ;
synchronized ( lock) {
System . out. println ( "烟和外卖送来了" ) ;
lock. notifyAll ( ) ;
hasDinner = true ;
hasCigarette = true ;
}
}
}
三、保护性暂停模式
- 同步模式: 一个线程在等待另一个线程的执行结果
- 一个结果: 多个线程间通过一个对象来传递结果
- JDK 中,join实现的底层,就是保护性暂停
1. 无限等待
package com. nike. erick. d04 ;
import java. util. ArrayList ;
import java. util. concurrent. TimeUnit ;
public class Demo06 {
private static GuardResponse guardResponse = new GuardResponse ( ) ;
public static void main ( String [ ] args) {
new Thread ( ( ) -> System . out. println ( guardResponse. getResponse ( ) . getClass ( ) . getSimpleName ( ) ) ) . start ( ) ;
new Thread ( ( ) -> guardResponse. setResponse ( new ArrayList < > ( ) ) ) . start ( ) ;
}
}
class GuardResponse {
private Object response;
public Object getResponse ( ) {
synchronized ( this ) {
while ( response == null ) {
try {
System . out. println ( "暂无获取到资源" ) ;
this . wait ( ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
}
return response;
}
}
public void setResponse ( Object response) {
synchronized ( this ) {
try {
System . out. println ( "开始赋值" ) ;
TimeUnit . SECONDS. sleep ( 2 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
this . response = response;
this . notify ( ) ;
}
}
}
2. 超时等待
package com. nike. erick. d04 ;
import java. util. ArrayList ;
import java. util. concurrent. TimeUnit ;
public class Demo06 {
private static GuardResponse guardResponse = new GuardResponse ( ) ;
public static void main ( String [ ] args) {
new Thread ( ( ) -> System . out. println ( guardResponse. getResponse ( 2000 ) ) ) . start ( ) ;
new Thread ( ( ) -> {
try {
TimeUnit . SECONDS. sleep ( 1 ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
guardResponse. setResponse ( new ArrayList < > ( ) ) ;
} ) . start ( ) ;
}
}
class GuardResponse {
private Object response;
public Object getResponse ( long timeoutMills) {
synchronized ( this ) {
long startTime = System . currentTimeMillis ( ) ;
long passedTime = 0 ;
while ( response == null ) {
long leftTime = timeoutMills - passedTime;
if ( leftTime <= 0 ) {
break ;
}
try {
this . wait ( leftTime) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
passedTime = System . currentTimeMillis ( ) - startTime;
}
return response;
}
}
public void setResponse ( Object response) {
synchronized ( this ) {
this . response = response;
this . notify ( ) ;
}
}
}
四、生产者消费者
阻塞队列 多个生产者及多个消费者 异步消费 消息队列,先入先得,是有容量限制的,满时不再添加消息,空时不再消费消息 JDK中各种阻塞队列 ,就是用的这种方式
package com. nike. erick. d06 ;
import java. util. LinkedList ;
public class Demo01 {
private static MessageBroker < String > messageBroker = new MessageBroker < > ( 2 ) ;
public static void main ( String [ ] args) {
for ( int i = 0 ; i < 1 ; i++ ) {
int round = i;
new Thread ( ( ) -> messageBroker. addMessage ( "hello-" + round) ) . start ( ) ;
}
for ( int i = 0 ; i < 4 ; i++ ) {
new Thread ( ( ) -> messageBroker. getMessage ( ) ) . start ( ) ;
}
}
}
class MessageBroker < T > {
private int queueCapacity;
public LinkedList < T > pool = new LinkedList < > ( ) ;
public MessageBroker ( int queueCapacity) {
this . queueCapacity = queueCapacity;
}
public synchronized void addMessage ( T element) {
while ( pool. size ( ) == this . queueCapacity) {
try {
System . out. println ( Thread . currentThread ( ) . getName ( ) + "消息积压,请等待" ) ;
this . wait ( ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
}
pool. addFirst ( element) ;
System . out. println ( Thread . currentThread ( ) . getName ( ) + "消息添加成功" ) ;
this . notifyAll ( ) ;
}
public synchronized T getMessage ( ) {
while ( pool. isEmpty ( ) ) {
try {
System . out. println ( "暂无消息,请等待" ) ;
this . wait ( ) ;
} catch ( InterruptedException e) {
e. printStackTrace ( ) ;
}
}
T element = pool. removeLast ( ) ;
System . out. println ( "消费成功" ) ;
this . notifyAll ( ) ;
return element;
}
}