這是比較推薦的一種方式,不用控制線程啓動的順序. 思路簡單,直接上代碼,若是須要增長打印次數也很方便.java
static class PrintSemaphore implements Runnable {
String printValue;
Semaphore selfSemaphore;
Semaphore nextSemaphore;
public void setSelfSemaphore(Semaphore selfSemaphore) {
this.selfSemaphore = selfSemaphore;
}
public void setNextSemaphore(Semaphore nextSemaphore) {
this.nextSemaphore = nextSemaphore;
}
public PrintSemaphore(String printValue) {
this.printValue = printValue;
}
@Override
public void run() {
while (true) {
try {
selfSemaphore.acquire();//獲取信號量,s - 1
System.out.println(printValue);
nextSemaphore.release();//釋放信號量,s + 1
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
//信號量,用於控制同時允許訪問的線程數量
Semaphore sA = new Semaphore(1);
Semaphore sB = new Semaphore(0);
Semaphore sC = new Semaphore(0);
PrintSemaphore printSemaphoreA = new PrintSemaphore("A");
PrintSemaphore printSemaphoreB = new PrintSemaphore("B");
PrintSemaphore printSemaphoreC = new PrintSemaphore("C");
printSemaphoreA.setSelfSemaphore(sA);
printSemaphoreA.setNextSemaphore(sB);
printSemaphoreB.setSelfSemaphore(sB);
printSemaphoreB.setNextSemaphore(sC);
printSemaphoreC.setSelfSemaphore(sC);
printSemaphoreC.setNextSemaphore(sA);
ExecutorService exe = Executors.newCachedThreadPool();
exe.execute(printSemaphoreB);
exe.execute(printSemaphoreC);
exe.execute(printSemaphoreA);
}
複製代碼
看一個序列CABC,能夠得出:
CA, 打印A須要拿到前面C的鎖(表明C已經執行完),以及它本身的鎖.
AB,打印B須要拿到前面A的鎖(表明A已經執行完),以及它本身的鎖.
BC,打印A須要拿到前面B的鎖(表明B已經執行完),以及它本身的鎖.
只要打印ABC的線程,按順序啓動,即B啓動時A已經執行完一次,C啓動時B已經執行完一次.那麼序列的順序就是能夠保證的.ide
打印A線程先啓動,拿到C+A鎖,執行完後,釋放A鎖,並notifyAll.而後在C鎖上等待.
在間隔時間段後,打印B線程啓動,它請求A鎖並拿到,而後 拿到本身的B鎖,打印B.
,釋放B鎖,並notifyAll.而後在A鎖上等待.
注意此時:打印A線程 wait C,打印B線程 wait A
在間隔時間段後,打印C線程啓動,它請求B鎖並拿到,而後 拿到本身的C鎖,打印C.
,釋放C鎖,並notifyAll.而後在B鎖上等待.
這時咱們發現打印A線程的條件知足了,它能夠獲得C鎖和本身的A鎖.繼續循環
注意此時:打印B線程 wait A,打印C線程 wait B
打印ABCui
class PrintThreadSyn implements Runnable {
// 打印值
String value;
// 前面的鎖
Object preLock;
public void setPreLock(Runnable runnable) {
preLock = runnable;
}
public PrintThreadSyn(String value) {
this.value = value;
}
@Override
public void run() {
synchronized (preLock) {
while (true) {
synchronized (this) {
System.out.println(value);
this.notifyAll();
}
try {
preLock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) throws InterruptedException {
// ------------------------------synchronized--ABC-----------------------------
// 循環打印ABC
PrintThreadSyn threadA = new PrintThreadSyn("A");
PrintThreadSyn threadB = new PrintThreadSyn("B");
PrintThreadSyn threadC = new PrintThreadSyn("C");
threadA.setPreLock(threadC);
threadB.setPreLock(threadA);
threadC.setPreLock(threadB);
new Thread(threadA).start();
Thread.sleep(500);
new Thread(threadB).start();
Thread.sleep(500);
new Thread(threadC).start();
}
複製代碼
打印AB 只須要簡化代碼,對類無改動this
// 循環打印AB
PrintThreadSyn threadA = new PrintThreadSyn("A");
PrintThreadSyn threadB = new PrintThreadSyn("B");
threadA.setPreLock(threadB);
threadB.setPreLock(threadA);
new Thread(threadA).start();
Thread.sleep(500);
new Thread(threadB).start();
複製代碼
思路是同樣的,用ReentrantLock+Condition代替syn+notify+wait.spa
class PrintThreadReentrantLock implements Runnable {
String value;
ReentrantLock lock;
Condition preCondition;
Condition selfCondition;
public void setLock(ReentrantLock lock) {
this.lock = lock;
}
public void setPreCondition(Condition condition) {
this.preCondition = condition;
}
public void setSelfCondition(Condition condition) {
this.selfCondition = condition;
}
public PrintThreadReentrantLock(String value) {
this.value = value;
}
@Override
public void run() {
lock.lock();
while (true) {
System.out.println(value);
selfCondition.signalAll();
try {
preCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
PrintThreadReentrantLock threadA = new PrintThreadReentrantLock("A");
PrintThreadReentrantLock threadB = new PrintThreadReentrantLock("B");
PrintThreadReentrantLock threadC = new PrintThreadReentrantLock("C");
ReentrantLock reentrantLock = new ReentrantLock();
threadA.setLock(reentrantLock);
threadB.setLock(reentrantLock);
threadC.setLock(reentrantLock);
Condition conditionA = reentrantLock.newCondition();
Condition conditionB = reentrantLock.newCondition();
Condition conditionC = reentrantLock.newCondition();
threadA.setSelfCondition(conditionA);
threadB.setSelfCondition(conditionB);
threadC.setSelfCondition(conditionC);
threadA.setPreCondition(conditionC);
threadB.setPreCondition(conditionA);
threadC.setPreCondition(conditionB);
new Thread(threadA).start();
Thread.sleep(500);
new Thread(threadB).start();
Thread.sleep(500);
new Thread(threadC).start();
}
複製代碼
打印AB 只須要簡化代碼,對類無改動線程
PrintThreadReentrantLock threadA = new PrintThreadReentrantLock("A");
PrintThreadReentrantLock threadB = new PrintThreadReentrantLock("B");
ReentrantLock reentrantLock = new ReentrantLock();
threadA.setLock(reentrantLock);
threadB.setLock(reentrantLock);
Condition conditionA = reentrantLock.newCondition();
Condition conditionB = reentrantLock.newCondition();
threadA.setSelfCondition(conditionA);
threadB.setSelfCondition(conditionB);
threadA.setPreCondition(conditionB);
threadB.setPreCondition(conditionA);
new Thread(threadA).start();
Thread.sleep(500);
new Thread(threadB).start();
複製代碼