如何让特定线程成为下一个进入同步块的线程?

时间:2011-07-04 16:57:40

标签: java multithreading

我在接受采访时被问到这个问题。

  

有四个线程t1,t2,t3和t4。 t1正在执行同步块,其他线程正在等待t1完成。你会做什么操作,以便在t1之后执行t3。

我回答说join方法应该可以解决问题,但看起来它不是正确的答案。他给出的原因是,join方法和setPriority方法不适用于处于等待状态的线程。

我们可以做到这一点吗?如果是,怎么样?

7 个答案:

答案 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();
            }

    }}

}

}