面试常考题,整理几种常见实现,侵删
1. 使用wait()和notify()
public class PrintABCUsingWaitNotify {
/**
* 实现步骤:
* 定义一个共享对象用来同步。
* 使用wait()让线程进入等待状态。
* 使用notify()唤醒下一个线程。
*/
private final Object lock = new Object();
private int state = 0; // 0:A 1:B 2:C
@Test
public void testPrintABC() {
PrintABCUsingWaitNotify task = new PrintABCUsingWaitNotify();
Thread threadA = new Thread(task::printA);
Thread threadB = new Thread(task::printB);
Thread threadC = new Thread(task::printC);
threadA.start();
threadB.start();
threadC.start();
}
public void printA() {
synchronized (lock) {
for (int i = 0; i < 10; i++) {
while (state != 0) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print("A");
state = 1;
lock.notifyAll();
}
}
}
public void printB() {
synchronized (lock) {
for (int i = 0; i < 10; i++) {
while (state != 1) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print("B");
state = 2;
lock.notifyAll();
}
}
}
public void printC() {
synchronized (lock) {
for (int i = 0; i < 10; i++) {
while (state != 2) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.print("C");
state = 0;
lock.notifyAll();
}
}
}
}
2. 使用ReentrantLock和Condition
public class PrintABCUsingReentrantLock {
/**
* 实现步骤
* 定义一个ReentrantLock和多个Condition。
* 每个线程等待相应的Condition,当符合条件时打印字符并唤醒下一个线程。
*/
private final Lock lock = new ReentrantLock();
private final Condition conditionA = lock.newCondition();
private final Condition conditionB = lock.newCondition();
private final Condition conditionC = lock.newCondition();
private int state = 0; // 0:A 1:B 2:C
@Test
public void testPrintABC() throws InterruptedException {
PrintABCUsingReentrantLock task = new PrintABCUsingReentrantLock();
Thread threadA = new Thread(task::printA);
Thread threadB = new Thread(task::printB);
Thread threadC = new Thread(task::printC);
threadA.start();
threadB.start();
threadC.start();
}
public void printA() {
lock.lock();
try {
for (int i = 0; i < 10; i++) {
while (state != 0) {
conditionA.await();
}
System.out.print("A");
state = 1;
conditionB.signal();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printB() {
lock.lock();
try {
for (int i = 0; i < 10; i++) {
while (state != 1) {
conditionB.await();
}
System.out.print("B");
state = 2;
conditionC.signal();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void printC() {
lock.lock();
try {
for (int i = 0; i < 10; i++) {
while (state != 2) {
conditionC.await();
}
System.out.print("C");
state = 0;
conditionA.signal();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
3. ReentrantLock和Condition的另一种写法
public class SyncPrinter implements Runnable {
private final int PRINT_COUNT = 10;
private final ReentrantLock reentrantLock;
private final Condition thisCondition;
private final Condition nextCondition;
private final char printChar;
public SyncPrinter(ReentrantLock reentrantLock, Condition thisCondition, Condition nextCondition, char printChar) {
this.reentrantLock = reentrantLock;
this.thisCondition = thisCondition;
this.nextCondition = nextCondition;
this.printChar = printChar;
}
@Override
public void run() {
reentrantLock.lock();
try {
for (int i = 0; i < PRINT_COUNT; i++) {
System.out.println(printChar);
nextCondition.signal();
if (i < PRINT_COUNT - 1) {
try {
thisCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} finally {
reentrantLock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
ReentrantLock lock = new ReentrantLock();
Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();
Condition conditionC = lock.newCondition();
Thread printA = new Thread(new SyncPrinter(lock, conditionA, conditionB, 'A'));
Thread printB = new Thread(new SyncPrinter(lock, conditionB, conditionC, 'B'));
Thread printC = new Thread(new SyncPrinter(lock, conditionC, conditionA, 'C'));
printA.start();
Thread.sleep(100);
printB.start();
Thread.sleep(100);
printC.start();
}
}
4. 使用信号量Semaphore
public class PrintABCUsingSemaphore {
/**
* 实现步骤
* 定义三个信号量semA、semB、semC。
* 每个线程在自己的信号量上等待,打印完成后释放下一个线程的信号量。
*/
private final Semaphore semA = new Semaphore(1);
private final Semaphore semB = new Semaphore(0);
private final Semaphore semC = new Semaphore(0);
@Test
public void testPrintABC() throws InterruptedException {
PrintABCUsingSemaphore task = new PrintABCUsingSemaphore();
Thread threadA = new Thread(task::printA);
Thread threadB = new Thread(task::printB);
Thread threadC = new Thread(task::printC);
threadA.start();
threadB.start();
threadC.start();
}
public void printA() {
try {
for (int i = 0; i < 10; i++) {
semA.acquire();
System.out.print("A");
semB.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void printB() {
try {
for (int i = 0; i < 10; i++) {
semB.acquire();
System.out.print("B");
semC.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void printC() {
try {
for (int i = 0; i < 10; i++) {
semC.acquire();
System.out.print("C");
semA.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}