三个线程顺序打印1-100
Synchronized
我们可以结合Sync和Object#notifyAll来完成,如下所示
public class Test001 {
// 锁,用于线程间通信
public static final Object LOCK = new Object();
// 数据
public static volatile int count = 0;
private static final Integer MAX = 100;
public static void main(String[] args) {
for(int i=0;i<3;i++) {
new Thread(new worker(i)).start();
}
}
public static class worker implements Runnable {
private Integer index;
public worker(Integer index) {
this.index = index;
}
@Override
public void run() {
while (count < MAX) {
synchronized (LOCK) {
try {
while (count % 3 != index) {
LOCK.wait();
}
System.out.println("Thread-" + index + " | count: " + count);
count++;
LOCK.notifyAll();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
ReentrantLock
我们可以使用ReentrantLock和Condition尝试解决这种问题。大概的解决思路就是先通过lock对资源加锁,然后通过condition指定的唤醒下一个线程。相信大家都已经发现,这种方式比Synchronized的优点就是sync只能唤醒一个线程或者全部唤醒来让大家竞争,但是通过condition我们可以唤醒指定线程,避免资源浪费。
public class Test002 {
private static final int WORKER_COUNT = 3;
private static volatile int countIndex = 0;
private static final ReentrantLock LOCK = new ReentrantLock();
public static void main(String[] args) {
final List<Condition> conditions = new ArrayList<>();
for (int i=0;i<WORKER_COUNT;i++) {
Condition condition = LOCK.newCondition();
conditions.add(condition);
Worker worker = new Worker(conditions, i);
worker.start();
}
}
static class Worker extends Thread {
List<Condition> conditions;
int index;
public Worker(List<Condition> conditions, int index) {
super("Thread-" + index);
this.conditions = conditions;
this.index = index;
}
private void singleNext() {
int nextIndex = (index + 1) % conditions.size();
conditions.get(nextIndex).signal();
}
@Override
public void run() {
while (true) {
LOCK.lock();
try {
System.out.println(this.getName() + " 开始运行...");
while (countIndex % 3 != index) {
if (countIndex > 100) {
singleNext();
System.out.println(this.getName() + " 已终止...");
return;
}
System.out.println(this.getName() + " 等待中...");
conditions.get(index).await();
}
if (countIndex > 100) {
singleNext();
System.out.println(this.getName() + " 已终止...");
return;
}
System.out.println(this.getName() + " count:" + countIndex);
countIndex++;
singleNext();
} catch (Exception e) {
e.printStackTrace();
} finally {
LOCK.unlock();
}
}
}
}
}
知识扩展
这种问题还有很多变种,如三个线程顺序打印ABC,三个线程按照要求顺序打印ABC等。
这些问题都是上线问题的变体,譬如把1-100换成ABC,常见的1-100转为ABC的代码转换如下所示:
for (int i = 0; i < 100; i ++) {
char ascii = (char)(65 + i%3);
}
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 程序员小航
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果