我正在回答以下面试问题:
一个进程有三个线程。第一个线程打印1 1 1...,第二个打印2 2 2...,第三个打印3 3 3...无休止。你如何安排这三个线程以打印1 2 3 1 2 3...
我想出了下面的代码,使用两个线程打印1 2 1 2 1 2
,但我无法找出如何从第三个线程在这里打印数字3
的条件。
public class PrintOneTwoThree {
private static boolean isFirst = true;
private static final Object lock = new Object();
public static void main(String[] args) {
// first thread
new Thread(() -> {
try {
synchronized (lock) {
for (;;) {
while (!isFirst) {
lock.wait();
}
System.out.print("1 ");
isFirst = false;
lock.notify();
}
}
} catch (InterruptedException ignored) {
}
}).start();
// second thread
new Thread(() -> {
try {
synchronized (lock) {
for (;;) {
while (isFirst) {
lock.wait();
}
System.out.print("2 ");
isFirst = true;
lock.notify();
}
}
} catch (InterruptedException ignored) {
}
}).start();
}
}
如何有效地解决这类问题?
public class PrintOneTwoThree {
public static void main(String[] args) {
Printers sp = new Printers();
ExecutorService executor = Executors.newFixedThreadPool(3);
executor.submit(new FirstNumberProducer(sp, 9));
executor.submit(new SecondNumberProducer(sp , 9));
executor.submit(new ThirdNumberProducer(sp , 9));
executor.shutdown();
}
}
class Printers {
Semaphore first = new Semaphore(1);
Semaphore second = new Semaphore(0);
Semaphore third = new Semaphore(0);
public void printFirstNumber() {
try {
first.acquire();
}catch(InterruptedException exception) {
}
System.out.print("1");
second.release();
}
public void printSecondNumber() {
try {
second.acquire();
}catch(InterruptedException exception) {
}
System.out.print("2");
third.release();
}
public void printThirdNumber() {
try {
third.acquire();
}catch(InterruptedException exception) {
}
System.out.print("3");
first.release();
}
}
class FirstNumberProducer implements Runnable {
Printers sp;
int index;
FirstNumberProducer(Printers sp , int index) {
this.sp = sp;
this.index = index;
}
@Override
public void run() {
for(int i = 1 ; i <= index ; i = i + 3 ) {
sp.printFirstNumber();
}
}
}
class SecondNumberProducer implements Runnable{
Printers sp;
int index;
SecondNumberProducer(Printers sp , int index) {
this.sp = sp;
this.index = index;
}
@Override
public void run() {
for(int i = 2 ; i <= index ; i = i + 3) {
sp.printSecondNumber();
}
}
}
class ThirdNumberProducer implements Runnable{
Printers sp;
int index;
ThirdNumberProducer(Printers sp , int index) {
this.sp = sp;
this.index = index;
}
@Override
public void run() {
for(int i = 3 ; i <= index ; i = i + 3) {
sp.printThirdNumber();
}
}
}
程序的输出是:
123123123
每次打印后,使用整数计数器和检查余数除以3和增量计数器来代替布尔标志。由于同一锁上会有几个线程等待,所以最好使用通知所有
。
private static int counter = 0;
new Thread(() -> {
try {
synchronized (lock) {
for (;;) {
while (counter % 3 != 0) {
lock.wait();
}
System.out.print("1 ");
++counter;
lock.notifyAll();
}
}
} catch (InterruptedException ignored) {
}
}).start();
//And the same stuff for other two threads just replacing value for remainder in if and value in print
下面是一个使用计数器一次为n
线程授予一个线程权限的一般工作示例:
public class PrintOneTwoThree {
private static int currentTask;
private static int totalThreads;
private static final Object lock = new Object();
public static void main(String[] args) {
currentTask = 0;
totalThreads = 3;
for (int i = 0; i < totalThreads; i++) {
createThread(i);
}
}
static void createThread(int id) {
new Thread(() -> {
try {
for (;;) {
synchronized (lock) {
while (currentTask != id) {
lock.wait();
}
System.out.print(id + 1 + " ");
currentTask = (currentTask + 1) % totalThreads;
lock.notifyAll();
}
}
}
catch (InterruptedException ignored) {}
}).start();
}
}
输出:
1 2 3 1 2 3 1 2 3 ...
试试吧!
几句话:
>
notify()
适用于2线程版本(因为变量上最多有一个其他线程阻塞),但如果一个线程退出关键部分,并且通知
s条件变量currentTask
可用,但错误的线程赢得了获取锁的竞争,则在3版本中会死锁。我不确定这里的notifyAll()
设计是否合适,因为只有一个线程可以取得进展,所以它似乎是重新检查条件谓词并使用notify()
的替身。
我移动了(;)的
在同步部分之外,以尽可能缩小线程安全范围。这个例子是人为设计的,因为如果你想要访问单个资源而不是别的什么,那么增加线程的开销是没有意义的——你也可以在单个线程中确定地执行它。在现实世界的例子中,线程将在(;)的
中的其他地方执行线程安全工作
循环,所以考虑到这一点进行设计似乎是合乎逻辑的。
采访中问 有三条线。第一条线打印100到199个数字。第二个线程打印200到299之间的数字。第三条线从300到399。执行的顺序是
这个问题是在电子艺术采访中提出的。 有三条线。第一个线程打印1到10个数字。第二个线程打印从11到20的数字。第三条线从21到30。现在这三个线程都在运行。然而,数字是按不规则的顺序打印的,如1、11、2、21、12等。 如果我想让数字按排序顺序打印,比如1,2。。。我该怎么处理这些线呢?
我试图创建一个实现,其中多个线程打印序列的备用值。这里thread1将打印1,4,7 thread2将打印2,5,8 thread3将打印3,6,9。我用的是原子整数和模函数。 下面的实现可以很好地工作,第一个线程打印1,4,7,第二个线程打印2,5,8,第三个线程打印3,6,9,但问题是没有保持顺序,即输出可能类似于1,3,2,4,5,7,8,6,9,而我希望保持顺序,因为正确的线程可以打印这些
问题内容: 我正在尝试同步三个线程以打印012012012012…。但是它不能正常工作。每个线程都分配有一个编号,当它从主线程接收到信号时将打印该编号。以下程序有问题,我无法捕获。 问题答案: 您需要更多的协调。该notify调用不会立即唤醒线程并强制其继续执行。相反,您可以考虑notify将电子邮件发送给线程以使其可以继续进行。想象一下,如果您想让3个朋友按顺序给您打电话。您向朋友1发送了一封电
有两个线程,一个是打印偶数,另一个是打印奇数。在下面自定义锁的帮助下,我想按顺序打印数字。问题出在打印一些数字后(显示的数字顺序正确。)线程越来越死机。我花了一个多小时还是找不到问题,对我来说一切都很好。
NowCoder 题目描述 请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。 解题思路 // java public ArrayList<arraylist> Print(TreeNode pRoot) { ArrayList<arraylist> ret = new ArrayList<>()