如題:使用三個執行緒交替列印ABC,直至100次代碼實戰
方法一:
使用notify()、wait()方法
public class PrintAbc {
/**
* 喚醒執行緒的狀態值 state: threadA = 0, threadB = 1, threadC =2,
*/
int state = 0;
/**
* 回圈技術,初始值0
*/
int count = 0;
public void print(PrintAbc printAbc) {
Thread threadA = new Thread(() -> {
extracted(printAbc, "A", 0, 1);
});
Thread threadB = new Thread(() -> {
extracted(printAbc, "B", 1, 2);
});
Thread threadC = new Thread(() -> {
extracted(printAbc, "C", 2, 0);
});
threadC.start();
threadB.start();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
threadA.start();
}
/**
* 交替列印abc,直至100次
*
* @param printAbc 鎖物件
* @param a 列印的字母, 對應A、B、C
* @param needState 當前執行緒對應的state狀態值
* @param nextState 喚醒下一個執行緒所需state狀態值
*/
private void extracted(PrintAbc printAbc, String a, int needState, int nextState) {
while (true) {
synchronized (printAbc) {
if (count >= 100) {
break;
}
if (printAbc.count < 100 && printAbc.state == needState) {
System.out.println(a);
printAbc.state = nextState;
printAbc.count++;
printAbc.notifyAll();
} else {
try {
printAbc.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
public static void main(String[] args) {
PrintAbc printAbc = new PrintAbc();
printAbc.print(printAbc);
}
}
上述代碼使用notify(),wait(),進行執行緒間的條件喚醒,state的初始狀態是0,對應執行緒A,所以第一次列印字母也一定是A
方法二
使用ReentrantLock的的Condition條件
public class PrintAbcByCondition {
/**
* 回圈計數初始值0
*/
static int count = 0;
public void print() {
ReentrantLock reentrantLock = new ReentrantLock();
Condition conditionA = reentrantLock.newCondition();
Condition conditionB = reentrantLock.newCondition();
Condition conditionC = reentrantLock.newCondition();
Thread threadA = new Thread(() -> {
while (true) {
try {
reentrantLock.lock();
// threadA進來列印A然后喚醒threadB
if (count < 100) {
System.out.println("A");
count++;
conditionB.signal();
}
conditionA.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
reentrantLock.unlock();
}
}
});
Thread threadB = new Thread(() -> {
while (true) {
try {
reentrantLock.lock();
// threadB進來就阻塞等待threadA使用完畢
conditionB.await();
if (count < 100) {
System.out.println("B");
count++;
conditionC.signal();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
reentrantLock.unlock();
}
}
});
Thread threadC = new Thread(() -> {
while (true) {
try {
reentrantLock.lock();
// threadC進來就阻塞等待threadB使用完畢
conditionC.await();
if (count < 100) {
System.out.println("C");
count++;
conditionA.signal();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
reentrantLock.unlock();
}
}
});
threadC.start();
threadB.start();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
threadA.start();
}
public static void main(String[] args) {
new PrintAbcByCondition().print();
}
}
使用ReentrantLock的的Condition條件,很容易能實作三個執行緒之間的交替列印,需要注意的一點就是執行緒A是需要第一個執行,可以看到代碼里threadA在等待1秒后在執行,也能確保是第一個進行列印,原因如下:
執行緒B和執行緒C中任意一個執行緒拿到鎖都需要等待條件成立,執行緒C依賴執行緒B,而執行緒B依賴執行緒A,所以他們會一直阻塞直至執行緒A執行
上述兩個方法中,核心問題就是如何實作執行緒間的條件喚醒,如方法一,我們可以自定義state狀態變數來與各個執行緒系結,每個執行緒都有自己對應的state狀態,當state變數當前值與執行緒自身期望的state值相同才喚醒當前執行緒,也可以使用juc中ReentrantLock的提供的Condition條件完成執行緒間的條件喚醒
至此,三個執行緒交替列印ABC100次的實作方法介紹完畢
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/502223.html
標籤:其他
