2

两个线程如何同时访问一个同步块?也就是说,我怎样才能让一个线程给另一个线程执行同步块的机会,即使在这个线程完成同一个同步块的执行之前?

4

5 回答 5

6

请参阅wait()notify()notifyAll()

编辑:对您问题的编辑不正确。sleep() 方法不会释放监视器

例如:

private static final Object lock = new Object();

public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(2);
    executorService.execute(new One());
    executorService.execute(new Two());
}

static class One implements Runnable {
    @Override
    public void run() {
        synchronized (lock) {
            System.out.println("(One) I own the lock");
            System.out.println("(One) Giving up the lock and waiting");
            try {
                lock.wait();
            } catch (InterruptedException e) {
                System.err.println("(One) I shouldn't have been interrupted");
            }
            System.out.println("(One) I have the lock back now");
        }
    }
}

static class Two implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            System.err.println("(Two) I shouldn't have been interrupted");
        }
        synchronized (lock) {
            System.out.println("(Two) Now I own the lock (Two)");
            System.out.println("(Two) Giving up the lock using notify()");
            lock.notify();
        }
    }
}
于 2011-07-21T21:12:22.173 回答
1

我可以查看一个线程是否调用wait()监视器对象的唯一方法。然后它会释放监视器并等待通知,而其他线程可以执行同步块。然后其他线程将不得不调用notify()/notifyAll(),所以第一个线程得到监视器并继续。

于 2011-07-21T21:15:20.883 回答
1

线程可以使用lock.wait(). 然后另一个线程可以拿起监视器并进入同步块。

例子:

public class MultipleThreadsInSynchronizedBlock {
    public static void main(String... args) {
        final Object lock = new Object();
        Runnable runnable = new Runnable() {
            public void run() {
                synchronized (lock) {
                    System.out.println("Before wait");
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                    }
                    System.out.println("After wait");
                }
            }
        };
        new Thread(runnable).start();
        new Thread(runnable).start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }

        synchronized (lock) {
            lock.notifyAll();
        }
    }
}

这打印:

Before wait
Before wait
After wait
After wait

然而,允许互斥块以非原子方式运行并不是“黑客”。如果你要使用像这样的非常低级的同步原语,你需要知道你在做什么。

于 2011-07-21T21:15:08.123 回答
1

听起来您可能要考虑使用多个同步块,特别是如果有一个线程被捕获的阻塞操作并因此阻塞了另一个想要在块中执行其他内容的线程。

于 2011-07-21T21:13:50.527 回答
1

同步块是(根据定义)一次只能由一个线程访问的代码块。说您希望另一个线程进入这个块,而另一个线程当前也在处理它,确实使同步块方案无用。

您可能希望将同步块拆分为许多其他块。

于 2011-07-21T21:14:09.447 回答