我在接受采访时被问到这个问题。
有四个线程t1,t2,t3和t4。 t1正在执行同步块,其他线程正在等待t1完成。你会做什么操作,以便在t1之后执行t3。
我回答说join方法应该可以解决问题,但看起来它不是正确的答案。他给出的原因是,join方法和setPriority方法不适用于处于等待状态的线程。
我们可以做到这一点吗?如果是,怎么样?
答案 0 :(得分:5)
您可以使用锁和条件。将相同条件传递给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();
}
}
}
答案 1 :(得分:4)
我想我会使用一些锁存器。 t1和t2之间的一次倒计时,t2和t3之间的另一次倒计时,t3和t4之间的最后一次倒计时。 T1以countDown结束,t2以等待开始同步部分。
这样,所有线程都可以并行执行预处理并恢复顺序部分的顺序。
我不能说它很优雅。
答案 2 :(得分:4)
每个线程应该只是在一个单独的对象上等待()。所以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();}
}
答案 3 :(得分:1)
我不知道任何标准方式,但我想我会传递某种令牌,只允许执行令牌的那个...其他人屈服()。因此t1在完成时会将令牌赋予t3。但也许有更好的方法可以做到这一点。
这也需要使用notifyAll()而不是notify()。
答案 4 :(得分:0)
您可能希望在t1的同步块中使用notify()
方法。
http://www.janeg.ca/scjp/threads/notify.html
编辑:
我在notify()
上面犯了一个错误,它将由JVM自行决定,但是如果t2和t4 join()
到t3那么这个方法应该有效。
答案 5 :(得分:0)
如果T1已执行,我们可以使用标志仅允许T3运行。 一旦T3执行完成,其余的线程就可以执行。
现在这可能不是一个优雅的解决方案。
但从采访的角度来看,这将展示你理解等待和notifyall。
但又取决于接受采访的人。
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();
}
}
答案 6 :(得分:-1)
package producer.consumer;
import java.util.ArrayList; import java.util.List;
public class 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实现了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();
}
}}
}
}