java 如何让特定线程成为下一个进入同步块的线程?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6574218/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I get a specific thread to be the next one to enter a synchronized block?
提问by Vinoth Kumar C M
I was asked this in an interview.
我在一次采访中被问到这个问题。
There are four threads t1,t2,t3 and t4. t1 is executing a synchronized block and the other threads are waiting for t1 to complete. What operation would you do, so that t3 executes after t1.
有四个线程 t1、t2、t3 和 t4。t1 正在执行同步块,其他线程正在等待 t1 完成。你会做什么操作,让t3在t1之后执行。
I answered that join method should do the trick, but it looks like it isn't the right answer.The reason he gave was, the join method and the setPriority method would not work on threads that are wait state.
我回答说 join 方法应该可以解决问题,但看起来这不是正确的答案。他给出的原因是,join 方法和 setPriority 方法不适用于处于等待状态的线程。
Can we achieve this? If yes, how?
我们能做到这一点吗?如果是,如何?
采纳答案by extraneon
I think i would use some latches. One countdownlatch between t1 and t2, another one between t2 and t3, the last one between t3 and t4. T1 Ends with countDown, and t2 starts the to be synchronized part with await.
我想我会使用一些闩锁。在 t1 和 t2 之间倒计时一次,在 t2 和 t3 之间倒计时,最后一次在 t3 和 t4 之间。T1以countDown结束,t2以await开始要同步的部分。
That way all threads can do preprocessing in parallel and restore order for the sequential part.
这样所有线程都可以并行进行预处理并恢复顺序部分的顺序。
I can't say it's elegant though.
我不能说它很优雅。
回答by Victor Sorokin
You can use locks and conditions. Pass same condition to both t1 and t3:
您可以使用锁和条件。将相同的条件传递给 t1 和 t3:
class Junk {
private static class SequencedRunnable implements Runnable {
private final String name;
private final Lock sync;
private final Condition toWaitFor;
private final Condition toSignalOn;
public SequencedRunnable(String name, Lock sync, Condition toWaitFor, Condition toSignalOn) {
this.toWaitFor = toWaitFor;
this.toSignalOn = toSignalOn;
this.name = name;
this.sync = sync;
}
public void run() {
sync.lock();
try {
if (toWaitFor != null)
try {
System.out.println(name +": waiting for event");
toWaitFor.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name + ": doing useful stuff...");
if (toSignalOn != null)
toSignalOn.signalAll();
} finally {
sync.unlock();
}
}
}
public static void main(String[] args) {
Lock l = new ReentrantLock();
Condition start = l.newCondition();
Condition t3AfterT1 = l.newCondition();
Condition allOthers = l.newCondition();
Thread t1 = new Thread(new SequencedRunnable("t1", l, start, t3AfterT1));
Thread t2 = new Thread(new SequencedRunnable("t2", l, allOthers, allOthers));
Thread t3 = new Thread(new SequencedRunnable("t3", l, t3AfterT1, allOthers));
Thread t4 = new Thread(new SequencedRunnable("t4", l, allOthers, allOthers));
t1.start();
t2.start();
t3.start();
t4.start();
l.lock();
try {
start.signalAll();
} finally {
l.unlock();
}
}
}
回答by M Platvoet
Every thread should simply wait() on a separate object. So t3 should wait on t3Mutex. You could then simply notify that specific thread.
每个线程都应该在一个单独的对象上简单地 wait() 。所以 t3 应该等待 t3Mutex。然后您可以简单地通知该特定线程。
final Object t1Mutex = new Object();
final Object t3Mutex = new Object();
...
synchronized(t3Mutex) {
//let thread3 sleep
while(condition) t3Mutex.wait();
}
...
synchronized(t1Mutex) {
//do work, thread1
synchronized(t3Mutex) {t3Mutex.notify();}
}
回答by mibollma
I don't know of any standard way but i guess i would pass around some kind of token and only the one that has the token is allowed to execute... the others yield(). So t1 would give the token to t3 when it's finished. But maybe there is a better way to do that.
我不知道有什么标准的方法,但我想我会传递某种令牌,只有拥有令牌的令牌才能执行……其他的 yield()。所以 t1 会在完成后将令牌交给 t3。但也许有更好的方法来做到这一点。
Also this would require to use notifyAll() instead of notify().
这也需要使用notifyAll() 而不是notify()。
回答by maple_shaft
You would want to use the notify()
method in the synchronization block of t1.
您可能希望notify()
在 t1 的同步块中使用该方法。
http://www.janeg.ca/scjp/threads/notify.html
http://www.janeg.ca/scjp/threads/notify.html
EDIT:
编辑:
I made a mistake about notify()
above, it will be at the JVM's discretion, however if t2 and t4 join()
to to t3 then this method should work.
我在notify()
上面犯了一个错误,这将由 JVM 自行决定,但是如果 t2 和 t4join()
到 t3 那么这个方法应该可以工作。
回答by Rahul Chandna
if T1 has executed we could then use a flag to allow only T3 to run. Once T3 execution completes then rest of the threads can execute.
如果 T1 已经执行,我们可以使用一个标志来只允许 T3 运行。一旦 T3 执行完成,其余的线程就可以执行了。
Now this may not be an elegant solution.
现在这可能不是一个优雅的解决方案。
But from an interview point of view, this will showcase that you understand wait and notifyall.
但是从面试的角度来看,这将表明您了解wait和notifyall。
But again depends on the person who is taking the interview.
但同样取决于参加面试的人。
public class ThreadSequenceTest implements Runnable {
Object o = new Object();
volatile boolean t3Only = false;
public void run() {
synchronized (o) {
if (Thread.currentThread().getName().equals("t1")) {
doSomething();
t3Only = true;
} else {
if (t3Only) {
if (Thread.currentThread().getName().equals("t3")) {
doSomething();
t3Only = false;
o.notifyAll();
} else {
try {
System.out.println("going to sleep " + Thread.currentThread().getName());
o.wait();
doSomething();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} else {
doSomething();
}
}
}
}
private void doSomething() {
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) throws InterruptedException {
ThreadSequenceTest threadSequenceTest = new ThreadSequenceTest();
Thread t1 = new Thread(threadSequenceTest);
t1.setName("t1");
Thread t2 = new Thread(threadSequenceTest);
t2.setName("t2");
Thread t3 = new Thread(threadSequenceTest);
t3.setName("t3");
Thread t4 = new Thread(threadSequenceTest);
t4.setName("t4");
t1.start();
Thread.sleep(500);
t2.start();
t3.start();
t4.start();
}
}
回答by user2579273
package producer.consumer;
包producer.consumer;
import java.util.ArrayList; import java.util.List;
导入 java.util.ArrayList; 导入 java.util.List;
public class ThreadInterComm {
公共类 ThreadInterComm {
public static void main(String args[]) {
List<Integer> sharedObject = new ArrayList<Integer>(1);
sharedObject.add(new Integer(0));
Runnable task = new MyTask(sharedObject);
Thread t1 = new Thread(task, "T1");
Thread t2 = new Thread(task, "T2");
Thread t3 = new Thread(task, "T3");
t1.start();
t2.start();
t3.start();
}
}
}
class MyTask implements Runnable {
类 MyTask 实现 Runnable {
private final List<Integer> sharedObject;
String name = "T1";//Initializing with T1
public MyTask(List<Integer> sharedObject) {
this.sharedObject = sharedObject;
}
public void run() {
synchronized (sharedObject) {
while (true) {//Or use a counter how many times to do the job
if (!name.equals(Thread.currentThread().getName())) {
try {
sharedObject.wait();//Let other Threads wait
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (name.equals(Thread.currentThread().getName())) {
int value = sharedObject.remove(0).intValue();
sharedObject.add(new Integer(++value));
System.out.println(Thread.currentThread().getName() + " : "
+ sharedObject.get(0));
if (Thread.currentThread().getName().equals("T1")) {
name = "T2";// give lock to t2
} else if (Thread.currentThread().getName().equals("T2")) {
name = "T3";// give lock to t3
} else if (Thread.currentThread().getName().equals("T3")) {
name = "T1";// give lock to t1
}
i--;
sharedObject.notifyAll();
}
}}
}
}
}