摘要
线程等待唤醒机制(wait/notify)。LockSupport中的park()和unpark()的作用分别是阻塞线程和解除阻塞线程。
synchronized和wait()/notify()方法package com.zhuangxiaoyan;
/**
* @Classname test1
* @Description TODO
* @Date 2021/11/25 19:43
* @Created by xjl
*/
public class test1 {
static Object objectlock = new Object();
public static void main(String[] args) {
new Thread(() -> {
//synchronized (objectlock) {
System.out.println(Thread.currentThread().getName() + "\t" + "----come in");
try {
objectlock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t " + "----被唤醒");
//}
}, "A").start();
new Thread(() -> {
//synchronized (objectlock) {
objectlock.notify();
System.out.println(Thread.currentThread().getName() + "\t " + "----被唤醒");
//}
}, "B").start();
}
}
0bject类中的wait、notify、notifyALL用于线程等待和唤醒的方法,都必须在synchronized内部执行必须用到关键字synchronized。先wait后notify才不会报错。
condition类 awit() 和signal()方法package com.zhuangxiaoyan;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Classname test1
* @Description TODO
* @Date 2021/11/25 19:43
* @Created by xjl
*/
public class test1 {
static Object objectlock = new Object();
static Lock lock=new ReentrantLock();
static Condition condition=lock.newCondition();
public static void main(String[] args) {
new Thread(() -> {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "\t" + "----come in");
try {
condition.await();
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t " + "----被唤醒");
}finally {
lock.unlock();
}
}, "A").start();
new Thread(() -> {
lock.lock();
try {
condition.signal();
System.out.println(Thread.currentThread().getName() + "\t " + "----被唤醒");
} finally {
lock.unlock();
}
}, "B").start();
}
}
线程先要获得并持有锁,必须在锁块(synchronized或lock)中必须要先等待后唤醒,线程才能够被唤醒。
LockSupport类 park()和unpark()方法LockSupport是用来创建锁和其他同步类的基本线程阻塞原语。LockSupport类使用了一种名为Permit(许可)的概念来做到阻塞和唤醒线程的功能,每个线程都有一个许可(permit),permit只有两个值1和零,默认是零。可以把许可看成是一种(0,1)信号量(Semaphore),但与Semaphore不同的是,许可的累加上限是1。
package com.zhuangxiaoyan;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Classname test1
* @Description TODO
* @Date 2021/11/25 19:43
* @Created by xjl
*/
public class test1 {
public static void main(String[] args) {
Runnable target;
Thread a=new Thread(()->{
try {
TimeUnit.SECONDS.sleep(3L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "\t" + "----come in");
LockSupport.park();//被阻塞....等待通知等待放行,它要通过需要许可证
System.out.println(Thread.currentThread().getName() + "\t " + "----被唤醒");
},"a");
a.start();
Thread b=new Thread(()->{
LockSupport.unpark(a);
System.out.println(Thread.currentThread().getName() + "\t " + "----被唤醒a线程");
});
b.start();
}
}
park和unpark是没有顺序的。
为什么可以先唤醒线程后阻塞线程?
因为unpark获得了一个凭证,之后再调用park方法,就可以名正言顺的凭证消费,故不会阻塞。
为什么唤醒两次后阻塞两次,但最终结果还会阻塞线程?
因为凭证的数量最多为1,连续调用两次unpark和调用一次unpark 效果一样,只会增加一个凭证;而调用两次park却需要消费两个凭证,证不够,不能放行。