两个线程如何同时访问同步块?也就是说,即使在此线程完成相同同步块的执行之前,如何让一个线程为其他线程提供执行同步块的机会呢?
答案 0 :(得分:5)
请参阅wait(),notify()和notifyAll()。
修改:您的问题的修改不正确。 sleep() method 不释放显示器。
例如:
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();
}
}
}
答案 1 :(得分:1)
听起来你可能想考虑使用多个同步块,特别是如果有一个阻塞操作,一个线程被捕获,从而阻塞另一个想要在块中执行其他操作的线程。
答案 2 :(得分:1)
同步块是一个代码块,可以(根据定义)一次只能由一个线程访问。 假设您希望另一个线程进入此块,而另一个线程当前也处理它,确实使同步块方案无效。
您可能希望将已同步的块拆分为许多其他块。
答案 3 :(得分: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
然而,允许互斥块以非原子方式运行并不是“黑客”。如果您打算使用这种非常低级的同步原语,您需要知道自己在做什么。
答案 4 :(得分:1)
我可以看到一个线程是否在监视器对象上调用wait()
的唯一方法。然后它将释放监视器并等待通知,而其他线程可以执行同步块。然后其他线程将不得不调用notify()/notifyAll()
,以便第一个线程获得监视器并继续。