題目要求:
請用“等待喚醒”機制編寫一個程序,要求:
第一個線程:遍歷1--1000所有的數字,在遍歷過程中,如果發現這個數字能同時被2,3,5,7整除,立即wait()退出等待,讓第二個線程進入。
第二個線程:運行後,將一個計數器 + 1,之後再喚醒等待的線程。
主線程中:休息2秒,讓兩個線程全部執行完畢,打印“計數器”的結果。
這題主要出的是線程通信的問題。但要注意鎖對象是在線程中傳遞,它的屬性值可以發生變化。而基本類型不能做爲鎖,它的包裝類如果做爲鎖的話,值不能發生變化,不然鎖會失。所以定義了一個類做爲鎖對象,鎖對象可以修改它的屬性值,因爲鎖本身的引用沒有變化。
答案:
package com.itheima.day13.essential;
/**
* @author by NewBoy
* @since 2020/3/4
*/
public class Demo31WaitNotify {
public static void main(String[] args) {
//創建鎖對象
Lock lock = new Lock();
WaitThread t1 = new WaitThread(lock);
t1.start();
NotifyThread t2 = new NotifyThread(lock);
t2.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("計數器結果是:" + t2.count);
}
}
/**
* 鎖對象,在線程中傳遞,但它的屬性值可以發生變化
* 而基本類型不能做爲鎖,它的包裝類如果做爲鎖的話,值不能發生變化,不然鎖會失效
* 所以定義了一個類做爲鎖對象,鎖對象可以修改它的屬性值,因爲鎖本身的引用沒有變化
*/
class Lock {
//標記:是否需要喚醒
boolean needNofity = false;
}
/**
* 第一個線程:遍歷1--1000所有的數字,在遍歷過程中,如果發現這個數字能同時被
* 2,3,5,7整除,立即wait()退出等待,讓第二個線程進入。
*/
class WaitThread extends Thread {
private Lock lock;
public WaitThread(Lock lock) {
this.lock = lock;
}
@Override
public void run() {
synchronized (lock) {
for (int i = 1; i <= 1000; i++) {
if (i % 2 == 0 && i % 3 == 0 && i % 5 == 0 && i % 7 == 0) {
try {
System.out.println(i + "=> 進入等待狀態");
//設置標記告訴另一個線程我需要喚醒,另一個線程如果通知就加1,否則不加
lock.needNofity = true;
//等待自己
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//喚醒別人
lock.notify();
}
}
}
}
/**
* 第二個線程:運行後,將一個計數器 + 1,之後再喚醒等待的線程。
*/
class NotifyThread extends Thread {
private Lock lock;
public NotifyThread(Lock lock) {
this.lock = lock;
}
//計數器
public int count = 0;
@Override
public void run() {
while (true) {
synchronized (lock) {
//判斷是否需要喚醒
if (lock.needNofity) {
//喚醒
lock.notify();
//計數器加1
System.out.println("喚醒" + (++count) + "次");
//將喚醒的標記設置爲false
lock.needNofity = false;
}
try {
//自己等待
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
運行結果:
210=> 進入等待狀態
喚醒1次
420=> 進入等待狀態
喚醒2次
630=> 進入等待狀態
喚醒3次
840=> 進入等待狀態
喚醒4次