1. 程式人生 > >Java並發編程原理與實戰二十一:線程通信wait&notify&join

Java並發編程原理與實戰二十一:線程通信wait&notify&join

ola run 原理 ons spa sta pro join() cto

wait和notify

wait和notify可以實現線程之間的通信,當一個線程執行不滿足條件時可以調用wait方法將線程置為等待狀態,當另一個線程執行到等待線程可以執行的條件時,調用notify可以喚醒等待的線程。需要強調的是,在調用wait和notify時需要先獲取鎖,否則會拋出IllegalMonitorException異常。notify方法隨機從等待的線程中喚醒一個線程執行,notifyAll方法喚醒所有的等待線程,這些線程競爭時間片。下面是一個使用wait和notify的例子:當寫線程將signal喚醒標誌為1時,讀線程才可以讀。

public class Demo {

private volatile int signal;



public synchronized int getSignal() {
System.out.println(Thread.currentThread().getName() + " 進入同步方法了");
if (signal != 1) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

return signal;

}

public synchronized void setSignal(int signal) {
System.out.println(Thread.currentThread().getName() + " 喚醒了");
this.signal = signal;
notifyAll();
}

public static void main(String[] args) {
Demo demo = new Demo();
TaskOne taskOne = new TaskOne(demo);

TaskTwo taskTwo = new TaskTwo(demo);

// 開啟讀線程

new Thread(taskOne).start();
new Thread(taskOne).start();
new Thread(taskOne).start();
new Thread(taskOne).start();

// 開啟寫線程

new Thread(taskTwo).start();
}

}

public class TaskOne implements Runnable {

private Demo demo;

public TaskOne(Demo demo) {
this.demo = demo;
}

@Override
public void run() {
demo.getSignal();
}
}

public class TaskTwo implements Runnable {

private Demo demo;

public TaskTwo(Demo demo) {
this.demo = demo;
}

@Override
public void run() {
demo.setSignal(1);
}

}

2.用wait和notify實現生產者和消費者

public class Table {

private int count;

private static final int MAX_COUNT = 10;

public synchronized void push() {
while (count >= MAX_COUNT) {
try {
System.out.println(Thread.currentThread().getName() + "桌子已放滿,生產者停止生產");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count++;

System.out.println(Thread.currentThread().getName() + "桌子上當前產品數量: "+ count);

// 桌上一有產品就喚醒消費者

notifyAll();
}

public synchronized void take() {
while (count <= 0) {
try {
System.out.println(Thread.currentThread().getName() + "桌子已空,消費者停止消費");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;

System.out.println(Thread.currentThread().getName() + "桌上剩余產品: " + count);

// 當桌子上的產品被消費完後喚醒生產者

notifyAll();
}

}

public class Productor implements Runnable {

private Table table;

public Productor(Table table) {
this.table = table;
}

@Override
public void run() {
while (true) {
table.push();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

}

public class Consumer implements Runnable {

private Table table;

public Consumer(Table table) {
this.table = table;
}

@Override
public void run() {
while (true) {
table.take();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

}

public class Demo {
public static void main(String[] args) {
Table table = new Table();
Productor productor = new Productor(table);
Consumer consumer = new Consumer(table);

new Thread(productor).start();
new Thread(productor).start();
new Thread(productor).start();
new Thread(productor).start();

new Thread(consumer).start();
new Thread(consumer).start();
new Thread(consumer).start();
new Thread(consumer).start();
new Thread(consumer).start();
new Thread(consumer).start();
}
}

2.join

調用join方法的線程會加塞到其他線程之前執行,被加塞的線程在調用join方法的線程執行完後才接著執行。

public class JoinDemo {

public void a(Thread joinThread) {
System.out.println("線程a開始執行...");
joinThread.start();
try {
// 當前線程阻塞直到joinThread執行完畢
joinThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("線程a執行結束...");
}

public void b() {
System.out.println("加塞線程開始執行...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("加塞線程執行結束...");
}

public static void main(String[] args) {
final JoinDemo demo = new JoinDemo();
final Thread joinThread = new Thread() {
@Override
public void run() {
demo.b();
}
};

new Thread() {
@Override
public void run() {
demo.a(joinThread);
}
}.start();
}
}

參考資料:

《java並發編程實戰》龍果學院

Java並發編程原理與實戰二十一:線程通信wait&notify&join