如題:使用三個線程交替列印ABC,直至100次代碼實戰 方法一: 使用notify()、wait()方法 public class PrintAbc { /** * 喚醒線程的狀態值 state: threadA = 0, threadB = 1, threadC =2, */ int state ...
如題:使用三個線程交替列印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次的實現方法介紹完畢