并发线程协作分析
1.wait与notify
实例
1. 管程法
在Object对象中有三个方法wait()、notify()、notifyAll(),它们的用途都是用来控制线程的状态。
wait()
该方法用来将当前线程置入休眠状态,直到在其他线程调用此对象的notify()方法或notifyAll()方法将其唤醒。
在调用wait()之前,线程必须要获得该对象的对象级别锁,因此只能在同步方法或同步块中调用wait()方法。进入wait()方法后,当前线程释放锁。在从wait()返回前,线程与其他线程竞争重新获得锁。如果调用wait()时,没有持有适当的锁,则抛出IllegalMonitorStateException,它是RuntimeException的一个子类,因此,不需要try-catch结构。
notify()
该方法唤醒在此对象监视器上等待的单个线程。如果有多个线程都在此对象上等待,则会随机选择唤醒其中一个线程,对其发出通知notify(),并使它等待获取该对象的对象锁。注意“等待获取该对象的对象锁”,这意味着,即使收到了通知,wait的线程也不会马上获取对象锁,必须等待notify()方法的线程释放锁才可以。和wait()一样,notify()也要在同步方法/同步代码块中调用。
总结两个方法:wait()使线程停止运行,notify()使停止运行的线程继续运行。
说了一大堆概念,可能有点绕,下面我们看两个例子来理解一下这两个方法的具体使用方式。
- wait()方法可以使调用该线程的方法释放持有当前对象的锁,然后从运行状态退出,进入等待队列,直到再次被唤醒。
- notify()方法可以随机唤醒等待队列中等待的一个线程,并使得该线程退出等待状态,进入可运行状态
wait()与notify()操作会释放锁吗?
在上面的例子中,我们多次强调了锁的问题,那么执行wait()方法后或notify()后,会释放掉持有对象的对象锁吗?我们通过下面的例子来实验一下:
public class ThreadWaitNotifyLockDemo {
public static void main(String[] args) throws Exception {
Object lock = new Object();
Thread waitThread1 = new Thread(() -> {
ThreadWait threadWait = new ThreadWait(lock);
threadWait.testWait();
});
Thread waitThread2 = new Thread(() -> {
ThreadWait threadWait = new ThreadWait(lock);
threadWait.testWait();
});
waitThread1.start();
waitThread2.start();
}
}
执行结果:
start wait........
start wait........
notifyAll
notifyAll也是来自于Object类的方法,其作用是唤醒在此对象监视器上等待的所有线程。其用法与notify()基本一致,只不过它会唤醒一个对象监视器上等待的全部线程,被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。
sleep
sleep方法的作用是让当前线程暂停指定的时间(毫秒),sleep方法是最简单的方法,在上述的例子中也用到过,比较容易理解。唯一需要注意的是其与wait方法的区别。
最简单的区别是,wait方法依赖于同步,而sleep方法可以直接调用。而更深层次的区别在于sleep方法只是暂时让出CPU的执行权,并不释放锁。而wait方法则需要释放锁。
————————————————
版权声明:本文为CSDN博主「wtopps」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wtopps/article/details/81431540
package thread;
//线程协作:管程法(生产者、消费者、产品、缓冲区)
public class TestWiteNotifall {
public static void main(String[] args) {
SynContainer synContainer = new SynContainer();
new Productor(synContainer).start();
new Cunsumer(synContainer).start();
}
}
//生产者
class Productor extends Thread{
SynContainer synContainer;
public Productor(SynContainer synContainer){
this.synContainer=synContainer;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
synContainer.push(new Chicken(i));
System.out.println("生产了"+i+"只");
}
}
}
//消费者
class Cunsumer extends Thread{
SynContainer synContainer;
public Cunsumer(SynContainer synContainer){
this.synContainer=synContainer;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("消费了第"+synContainer.pop().id+"只");
}
}
}
//产品
class Chicken{
int id;
public Chicken(int id) {
this.id = id;
}
}
//缓冲区
class SynContainer{
//定义一个容器
Chicken[] chickens=new Chicken[10];
//容器计数器
int count=0;
//生产者放入产品
public synchronized void push(Chicken chicken){
//如果容器满了,需要等待消费者消费
if(count==chickens.length){
//通知消费者进行消费,生产者则进行等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果没有满,则需要继续生产
chickens[count]=chicken;
count++;
//通知消费者进行消费
this.notifyAll();
}
//消费者消费产品
public synchronized Chicken pop(){
//判断能否消费
if(count==0){
//等待生产者生产,消费者等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果可以消费
count--;
Chicken chicken=chickens[count];
//吃完了,通知生产者生产
this.notifyAll();
return chicken;
}
}
2. 信号法
package thread;
import com.sun.xml.internal.fastinfoset.util.ValueArrayResourceException;
//信号灯法
public class TestPC {
public static void main(String[] args) {
TV tv=new TV();
new Performer(tv).start();
new Watch(tv).start();
}
}
//生产者
class Performer extends Thread{
TV tv;
public Performer(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if(i%2==0){
tv.play("节目--->"+i);
}else{
tv.play("广告--->"+i);
}
}
}
}
//消费者
class Watch extends Thread{
TV tv;
public Watch(TV tv) {
this.tv = tv;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
tv.watch();
}
}
}
class TV{
private String voice;
boolean falg = true;
public synchronized void play(String voice){
if(!falg){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("演员表演了:"+voice);
//通知观众观看
this.notifyAll();
this.voice=voice;
this.falg=!this.falg;
}
//观看
public synchronized void watch(){
if(falg){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("看节目:"+voice);
//通知表演节目
this.notifyAll();
this.falg=!this.falg;
}
}