How can I get a specific thread to be the next one to enter a synchronized block?
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 woul开发者_开发技巧d you do, so that t3 executes after 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.
Can we achieve this? If yes, how?
You can use locks and conditions. Pass same condition to both t1 and 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();
}
}
}
Every thread should simply wait() on a separate object. So t3 should wait on t3Mutex. You could then simply notify that specific thread.
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();}
}
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.
That way all threads can do preprocessing in parallel and restore order for the sequential part.
I can't say it's elegant though.
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.
Also this would require to use notifyAll() instead of notify().
You would want to use the notify()
method in the synchronization block of t1.
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.
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.
Now this may not be an elegant solution.
But from an interview point of view, this will showcase that you understand wait and 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();
}
}
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 implements 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();
}
}}
}
}
精彩评论