The semaphore
This is the preferred method without controlling the order in which threads are started. Simple idea, directly on the code, if you need to increase the number of printing is also very convenient.
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(a) {
while (true) {
try {
selfSemaphore.acquire();// Get semaphore, s-1
System.out.println(printValue);
nextSemaphore.release();// Release semaphore, s + 1
} catch (InterruptedException e) {
// TODO Auto-generated catch blocke.printStackTrace(); }}}}public static void main(String[] args) {
// The semaphore controls the number of threads allowed to access simultaneously
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);
}
Copy the code
Using synchronized
Analysis of the
Looking at A sequence called CABC, we can see that CA, printing A, takes the lock of C in front of it (indicating that C has finished), as well as its own lock. AB, printing B requires taking the previous lock of A (indicating that A has finished), as well as its own lock. BC, printing A requires taking the previous lock of B (indicating that B is done), as well as its own lock. Just print the threads of ABC and start them in order, that is, A has finished executing once when B starts and B has finished executing once when C starts. So the order of the sequence is guaranteed.
simulation
Print A line first start, get C+A lock, release A lock after execution, and notifyAll. Then wait on the C lock. After an interval, the print B thread starts, it requests A lock and takes it, then gets its own B lock, prints B., releases the B lock, and notifyAll. Then wait at lock A. Note: at this time to print A thread wait C, print B threads wait A after the interval time, print C thread start, request B lock and get it, then get their C lock, print c., release the lock C, and notifyAll. Then wait on lock B. At this point, we find that the condition for printing thread A is met, and it can get the C lock and its own A lock. Print thread B wait A, print thread C wait B print ABC
class PrintThreadSyn implements Runnable {
/ / print the value
String value;
// The front lock
Object preLock;
public void setPreLock(Runnable runnable) {
preLock = runnable;
}
public PrintThreadSyn(String value) {
this.value = value;
}
@Override
public void run(a) {
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-----------------------------
// Loop to print 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();
}
Copy the code
Printing AB simply simplifies the code, leaving the class unchanged
// Circularly print 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();
Copy the code
ReentrantLock
ReentrantLock+Condition instead of SYN +notify+wait
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(a) {
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();
}
Copy the code
Printing AB simply simplifies the code, leaving the class unchanged
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();
Copy the code