面试题目
给定三个线程A、B、C,线程A负责打印A,线程B负责打印B、线程C负责打印C,三个线程依次交替打印,输出格式如ABCABC……,打印10次结束。
1、volatile无锁实现
思路
使用一个volatile变量state来控制三个线程的打印顺序,state为0、1、2则分别打印A、B、C,
代码
public class NonLockDemo {
// 打印次数
private static final int PRINT_TIMES = 10;
private volatile int state;
public static void main(String[] args) {
NonLockDemo nonLockDemo = new NonLockDemo();
Thread thread1 = new Thread(nonLockDemo::printA);
Thread thread2 = new Thread(nonLockDemo::printB);
Thread thread3 = new Thread(nonLockDemo::printC);
thread1.start();
thread2.start();
thread3.start();
}
private void printA() {
for (int i = 0; i < PRINT_TIMES; i++) {
while (state != 0) {
Thread.yield(); // 让出CPU时间片,避免CPU空等待
}
System.out.print("A");
state = 1;
}
}
private void printB() {
for (int i = 0; i < PRINT_TIMES; i++) {
while (state != 1) {
Thread.yield();
}
System.out.print("B");
state = 2;
}
}
private void printC() {
for (int i = 0; i < PRINT_TIMES; i++) {
while (state != 2) {
Thread.yield();
}
System.out.print("C ");
state = 0;
}
}
}
2、Lock结合Condition实现
思路
使用Java中的管程模型的实现Lock、Condition来解决这个问题,Lock的互斥机制实现了同一时刻只有一个线程在写,Condition则负责协调各个线程的执行顺序。
代码
public class LockConditionDemo {
private static final int PRINT_TIMES = 10;
private static ReentrantLock lock = new ReentrantLock();
private static Condition conditionA = lock.newCondition();
private static Condition conditionB = lock.newCondition();
private static Condition conditionC = lock.newCondition();
private static volatile int count = 0;
public static void main(String[] args) {
Thread thread1 = new Thread(LockConditionDemo::printA);
Thread thread2 = new Thread(LockConditionDemo::printB);
Thread thread3 = new Thread(LockConditionDemo::printC);
thread1.start();
thread2.start();
thread3.start();
}
private static void printA() {
lock.lock();
try {
for (int i = 0; i < PRINT_TIMES; i++) {
while (count != 0) {
conditionA.await();
}
System.out.print("A ");
count = 1;
conditionB.signal();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
private static void printB() {
lock.lock();
try {
for (int i = 0; i < PRINT_TIMES; i++) {
while (count != 1) {
conditionB.await();
}
System.out.print("B ");
count = 2;
conditionC.signal();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
private static void printC() {
lock.lock();
try {
for (int i = 0; i < PRINT_TIMES; i++) {
while (count != 2) {
conditionC.await();
}
System.out.println("C");
count = 3;
conditionA.signal();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
3、Semaphore实现
思路
使用信号量Semaphore来实现控制线程并发的数量,Semaphore内部维护了一个计数器,如果计数器的值大于等于1代表有资源可以访问,使用acquire方法可以使计数器的值减1,使用release方法可以使计数器的值加1。
代码
public class SemaphoreDemo {
private static final int PRINT_TIMES = 10;
private static Semaphore semaphore1 = new Semaphore(1);
private static Semaphore semaphore2 = new Semaphore(0);
private static Semaphore semaphore3 = new Semaphore(0);
public static void main(String[] args) {
Thread thread1 = new Thread(SemaphoreDemo::printA);
Thread thread2 = new Thread(SemaphoreDemo::printB);
Thread thread3 = new Thread(SemaphoreDemo::printC);
thread1.start();
thread2.start();
thread3.start();
}
private static void printA() {
try {
for (int i = 0; i < PRINT_TIMES; i++) {
semaphore1.acquire();
System.out.print("A ");
semaphore2.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void printB() {
try {
for (int i = 0; i < PRINT_TIMES; i++) {
semaphore2.acquire();
System.out.print("B ");
semaphore3.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void printC() {
try {
for (int i = 0; i < PRINT_TIMES; i++) {
semaphore3.acquire();
System.out.println("C");
semaphore1.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}