简体   繁体   English

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

[英]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、t2、t3 和 t4。 t1 is executing a synchronized block and the other threads are waiting for t1 to complete. t1 正在执行同步块,其他线程正在等待 t1 完成。 What operation would you do, so that t3 executes after 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 方法不适用于等待 state 的线程。

Can we achieve this?我们能做到这一点吗? If yes, how?如果是,如何?

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

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 和 t2 之间有一个倒计时,在 t2 和 t3 之间有另一个,在 t3 和 t4 之间有最后一个。 T1 Ends with countDown, and t2 starts the to be synchronized part with await. 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.我不能说它很优雅。

Every thread should simply wait() on a separate object.每个线程都应该在单独的 object 上简单地 wait()。 So t3 should wait on t3Mutex.所以 t3 应该等待 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 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().我不知道任何标准方式,但我想我会传递某种令牌,并且只允许执行具有令牌的令牌......其他的 yield()。 So t1 would give the token to t3 when it's finished.所以 t1 完成后会将令牌交给 t3。 But maybe there is a better way to do that.但也许有更好的方法来做到这一点。

Also this would require to use notifyAll() instead of notify().这也需要使用 notifyAll() 而不是 notify()。

if T1 has executed we could then use a flag to allow only T3 to run.如果 T1 已经执行,我们可以使用一个标志来只允许 T3 运行。 Once T3 execution completes then rest of the threads can execute.一旦 T3 执行完成,则线程的 rest 可以执行。

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();

    }
}

You would want to use the notify() method in the synchronization block of t1.您可能希望在 t1 的同步块中使用notify()方法。

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 和 t4 join() to t3 那么这个方法应该可以工作。

package producer.consumer; package producer.consumer;

import java.util.ArrayList;导入 java.util.ArrayList; import java.util.List;导入 java.util.List;

public class ThreadInterComm {公共 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 { 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();
            }

    }}

}

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM