信号量的方式
这是比较推荐的一种方式,不用控制线程启动的顺序. 思路简单,直接上代码,如果需要增加打印次数也很方便.
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);
}
使用synchronized
分析
看一个序列CABC,可以得出:
CA, 打印A需要拿到前面C的锁(代表C已经执行完),以及它自己的锁.
AB,打印B需要拿到前面A的锁(代表A已经执行完),以及它自己的锁.
BC,打印A需要拿到前面B的锁(代表B已经执行完),以及它自己的锁.
只要打印ABC的线程,按顺序启动,即B启动时A已经执行完一次,C启动时B已经执行完一次.那么序列的顺序就是可以保证的.
模拟
打印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
打印ABC
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 只需要简化代码,对类无改动
// 循环打印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
思路是一样的,用ReentrantLock+Condition代替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() {
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();