面试题
有三个线程ABC分别向一个数组中写入a,l,i,要求最终的写入结果形如alialiali...写入次数由A线程决定
解法1:使用Object的 wait 和 notify
package org.example;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Sync1 {
List<Character> result = new ArrayList<>(); // 共享数组
volatile int total = 5; // 总写入次数(由A线程决定)
volatile int current = 0; // 当前写入次数
volatile String currentThread = "A"; // 当前执行线程标识
final Object lock = new Object(); // 同步锁
Runnable a = () -> {
while (true) {
synchronized (lock) {
// 等待当前执行线程为A且未达到总次数
while (!currentThread.equals("A") && current < total) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (current >= total) break; // 达到总次数退出
result.add('a');
current++; // 仅A线程递增计数器
currentThread = "B"; // 切换到B线程
lock.notifyAll(); // 通知其他线程
}
}
};
Runnable b = () -> {
while (true) {
synchronized (lock) {
// 等待当前执行线程为B且未达到总次数
while (!currentThread.equals("B") && current <= total) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
result.add('l');
currentThread = "C"; // 切换到C线程
lock.notifyAll();
if (current >= total) break;
}
}
};
Runnable c = () -> {
while (true) {
synchronized (lock) {
// 等待当前执行线程为C且未达到总次数
while (!currentThread.equals("C") && current <= total) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
result.add('i');
currentThread = "A"; // 切换回A线程
lock.notifyAll();
if (current >= total) break;
}
}
};
private void test() throws InterruptedException {
Thread threada = new Thread(a);
Thread threadb = new Thread(b);
Thread threadc = new Thread(c);
threada.start();
threadb.start();
threadc.start();
threada.join();
threadb.join();
threadc.join();
System.out.println(Arrays.toString(result.toArray()));
}
public static void main(String[] args) {
try {
new Sync3().test();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
解法2:使用 Lock.Condition 的 await 和 signal
package org.example;
import java.util.concurrent.locks.*;
import java.util.concurrent.atomic.*;
import java.util.*;
public class Sync2 {
private static final int TOTAL = 5; // 由A线程决定的总写入次数
private static final List<Character> result = Collections.synchronizedList(new ArrayList<>());
private static final AtomicInteger current = new AtomicInteger(0);
private static final AtomicBoolean termination = new AtomicBoolean(false);
private static final Lock lock = new ReentrantLock();
private static final Condition aCond = lock.newCondition();
private static final Condition bCond = lock.newCondition();
private static final Condition cCond = lock.newCondition();
public static void main(String[] args) throws InterruptedException {
Thread a = new Thread(SyncWriter::threadA);
Thread b = new Thread(SyncWriter::threadB);
Thread c = new Thread(SyncWriter::threadC);
a.start();
b.start();
c.start();
Thread.sleep(10);
// 初始触发A线程
lock.lock();
System.out.println("main 获取锁");
try {
aCond.signal();
} finally {
lock.unlock();
System.out.println("main 释放锁");
}
a.join();
b.join();
c.join();
System.out.println(result);
}
private static void threadA() {
while (!termination.get()) {
lock.lock();
System.out.println("threadA 获取锁");
try {
aCond.await();
System.out.println("threadA 突破await");
if (termination.get()) break;
result.add('a');
int next = current.incrementAndGet();
if (next >= TOTAL) termination.set(true);
bCond.signal();
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
} finally {
lock.unlock();
System.out.println("threadA 释放锁");
}
}
System.out.println("threadA over");
}
private static void threadB() {
while (!termination.get()) {
lock.lock();
System.out.println("threadB 获取锁");
try {
bCond.await();
System.out.println("threadB 突破await");
result.add('l');
cCond.signal();
if (termination.get()) break;
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
} finally {
lock.unlock();
System.out.println("threadB 释放锁");
}
}
System.out.println("threadB over");
}
private static void threadC() {
while (!termination.get()) {
lock.lock();
System.out.println("threadC 获取锁");
try {
cCond.await();
System.out.println("threadC 突破await");
result.add('i');
aCond.signal();
if (termination.get()) break;
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
} finally {
lock.unlock();
System.out.println("threadC 释放锁");
}
}
System.out.println("threadC over");
}
}