wait() 是否释放所有锁?
Does wait() release all locks?
我编写这个程序是为了检查 thread_1 持有两个不同对象的锁:LOCK_OBJECT
和 FULL
使用 [=15] 在 LOCK_OBJECT
上进入等待模式=].我认为消费者不会获得 LOCK_OBJECT
锁,但印刷品不会。那么你有什么想念的吗?
为什么消费者会根据打印结果得到LOCK_OBJECT
锁?
这是我的代码:
public class TestSync {
private volatile Integer amount = 0;
private final Object LOCK_OBJECT = new Object();
private final Object FULL = new Object();
public void doubleSync() throws InterruptedException {
System.out.println("Producer trying to get LOCK_OBJECT lock ");
synchronized (LOCK_OBJECT) {
System.out.println("Producer get LOCK_OBJECT lock ");
Print.sleep(3000);
while (amount >= 0) {
synchronized (FULL) {
System.out.println("full!");
FULL.wait();
}
}
System.out.println("continue~");
amount++;
}
}
public void simpleSync() {
System.out.println("Consumer trying to get LOCK_OBJECT lock ");
synchronized (LOCK_OBJECT) {
System.out.println("Consumer get LOCK_OBJECT lock");
}
System.out.println("Consumer release LOCK_OBJECT lock");
}
public static void main(String[] args) throws InterruptedException {
AtomicInteger atomicInteger = new AtomicInteger(0);
ExecutorService threadPool = Executors.newFixedThreadPool(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
int index = atomicInteger.incrementAndGet();
System.out.println("create no " + index + " thread");
Thread t = new Thread(r, "one Thread-" + index);
return t;
}
});
threadPool.execute(() -> {
try {
new TestSync().doubleSync();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Print.sleep(1000);
ExecutorService executorService = Executors.newFixedThreadPool(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
int index = atomicInteger.incrementAndGet();
System.out.println("create no " + index + " thread");
Thread t = new Thread(r, "two Thread-" + index);
return t;
}
});
executorService.execute(() -> {
try {
new TestSync().simpleSync();
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
这是打印结果:
create no 1 thread
sleep 1000
Producer trying to get LOCK_OBJECT lock
Producer get LOCK_OBJECT lock
sleep 3000
create no 2 thread
Consumer trying to get LOCK_OBJECT lock
Consumer get LOCK_OBJECT lock
Consumer release LOCK_OBJECT lock
full!
您问题中的代码无法编译。什么是 Print
?它在您的代码中出现两次。一旦进入方法 main
Print.sleep(1000);
在下面的代码中,我简单地创建了一个名为 Print
的 class 并定义了一个静态方法 sleep
.
Locks 处理线程间共享的对象。在您的代码中,您为每个线程创建一个单独的 TestSync
对象。因此没有共享对象。尝试创建一个 TestSync
实例并将其发送到两个线程。此外,您不需要为每个线程单独设置 ExecutorService
。您可以使用单个 ExecutorService
来启动多个线程。下面的代码演示。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class TestSync {
private volatile Integer amount = 0;
private final Object LOCK_OBJECT = new Object();
private final Object FULL = new Object();
public void doubleSync() throws InterruptedException {
System.out.println("Producer trying to get LOCK_OBJECT lock ");
synchronized (LOCK_OBJECT) {
System.out.println("Producer get LOCK_OBJECT lock ");
Print.sleep(3000);
while (amount >= 0) {
synchronized (FULL) {
System.out.println("full!");
FULL.wait();
}
}
System.out.println("continue~");
amount++;
}
}
public void simpleSync() {
System.out.println("Consumer trying to get LOCK_OBJECT lock ");
synchronized (LOCK_OBJECT) {
System.out.println("Consumer get LOCK_OBJECT lock");
}
System.out.println("Consumer release LOCK_OBJECT lock");
}
public static void main(String[] args) throws InterruptedException {
AtomicInteger atomicInteger = new AtomicInteger(0);
ExecutorService threadPool = Executors.newFixedThreadPool(2, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
int index = atomicInteger.incrementAndGet();
System.out.println("create no " + index + " thread");
Thread t = new Thread(r, "Thread-" + index);
return t;
}
});
TestSync ts = new TestSync();
threadPool.execute(() -> {
try {
ts.doubleSync();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Print.sleep(1000);
threadPool.execute(() -> {
try {
ts.simpleSync();
} catch (Exception e) {
e.printStackTrace();
}
});
threadPool.shutdown();
}
}
class Print {
public static void sleep(long interval) {
System.out.println("sleep " + interval);
}
}
请注意,建议您在提交所有任务后调用接口 ExecutorService
的方法 shutdown()
。
这是我 运行 上述代码时的输出。
create no 1 thread
Producer trying to get LOCK_OBJECT lock
Producer get LOCK_OBJECT lock
sleep 1000
create no 2 thread
Consumer trying to get LOCK_OBJECT lock
sleep 3000
full!
如你所见,消费者没有获得锁。
Does wait()
release all locks?
没有。它只会释放您调用 wait()
的对象的锁。
至于您的代码的行为...我们无法完全解释它,因为它缺少一个关键方法:Print
.
但是,您似乎正在使用 TestSync
的多个实例。那将意味着生产者和消费者线程对于各自的锁对象具有不同的对象......并且没有互斥。
使用多个线程池也是一个坏主意(浪费),尤其是动态创建和销毁它们。与一次性线程相比,线程池的主要优点是(重要的)线程创建被分摊。但是当你关闭(或“丢失”)一个线程池时,线程无论如何都会被丢弃......并且必须为“下一个”线程池再次创建。
(这不会影响您的示例的行为。但这是一个坏习惯......如果您在实际应用程序中这样做,它很容易咬到您。)
课程: 使用原始互斥锁和 wait/notify 编程需要格外小心。最好使用更高级别的并发原语......在可能的情况下。
1.It 最好继续执行一个 ExecutorService 实现(因为出于性能原因,我们始终保持有限数量的线程处于活动状态)
2.wait() 确实释放了单个对象的锁,但之后所有线程(考虑相同的优先级)都同样有可能获得锁
我编写这个程序是为了检查 thread_1 持有两个不同对象的锁:LOCK_OBJECT
和 FULL
使用 [=15] 在 LOCK_OBJECT
上进入等待模式=].我认为消费者不会获得 LOCK_OBJECT
锁,但印刷品不会。那么你有什么想念的吗?
为什么消费者会根据打印结果得到LOCK_OBJECT
锁?
这是我的代码:
public class TestSync {
private volatile Integer amount = 0;
private final Object LOCK_OBJECT = new Object();
private final Object FULL = new Object();
public void doubleSync() throws InterruptedException {
System.out.println("Producer trying to get LOCK_OBJECT lock ");
synchronized (LOCK_OBJECT) {
System.out.println("Producer get LOCK_OBJECT lock ");
Print.sleep(3000);
while (amount >= 0) {
synchronized (FULL) {
System.out.println("full!");
FULL.wait();
}
}
System.out.println("continue~");
amount++;
}
}
public void simpleSync() {
System.out.println("Consumer trying to get LOCK_OBJECT lock ");
synchronized (LOCK_OBJECT) {
System.out.println("Consumer get LOCK_OBJECT lock");
}
System.out.println("Consumer release LOCK_OBJECT lock");
}
public static void main(String[] args) throws InterruptedException {
AtomicInteger atomicInteger = new AtomicInteger(0);
ExecutorService threadPool = Executors.newFixedThreadPool(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
int index = atomicInteger.incrementAndGet();
System.out.println("create no " + index + " thread");
Thread t = new Thread(r, "one Thread-" + index);
return t;
}
});
threadPool.execute(() -> {
try {
new TestSync().doubleSync();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Print.sleep(1000);
ExecutorService executorService = Executors.newFixedThreadPool(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
int index = atomicInteger.incrementAndGet();
System.out.println("create no " + index + " thread");
Thread t = new Thread(r, "two Thread-" + index);
return t;
}
});
executorService.execute(() -> {
try {
new TestSync().simpleSync();
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
这是打印结果:
create no 1 thread
sleep 1000
Producer trying to get LOCK_OBJECT lock
Producer get LOCK_OBJECT lock
sleep 3000
create no 2 thread
Consumer trying to get LOCK_OBJECT lock
Consumer get LOCK_OBJECT lock
Consumer release LOCK_OBJECT lock
full!
您问题中的代码无法编译。什么是 Print
?它在您的代码中出现两次。一旦进入方法 main
Print.sleep(1000);
在下面的代码中,我简单地创建了一个名为 Print
的 class 并定义了一个静态方法 sleep
.
Locks 处理线程间共享的对象。在您的代码中,您为每个线程创建一个单独的 TestSync
对象。因此没有共享对象。尝试创建一个 TestSync
实例并将其发送到两个线程。此外,您不需要为每个线程单独设置 ExecutorService
。您可以使用单个 ExecutorService
来启动多个线程。下面的代码演示。
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class TestSync {
private volatile Integer amount = 0;
private final Object LOCK_OBJECT = new Object();
private final Object FULL = new Object();
public void doubleSync() throws InterruptedException {
System.out.println("Producer trying to get LOCK_OBJECT lock ");
synchronized (LOCK_OBJECT) {
System.out.println("Producer get LOCK_OBJECT lock ");
Print.sleep(3000);
while (amount >= 0) {
synchronized (FULL) {
System.out.println("full!");
FULL.wait();
}
}
System.out.println("continue~");
amount++;
}
}
public void simpleSync() {
System.out.println("Consumer trying to get LOCK_OBJECT lock ");
synchronized (LOCK_OBJECT) {
System.out.println("Consumer get LOCK_OBJECT lock");
}
System.out.println("Consumer release LOCK_OBJECT lock");
}
public static void main(String[] args) throws InterruptedException {
AtomicInteger atomicInteger = new AtomicInteger(0);
ExecutorService threadPool = Executors.newFixedThreadPool(2, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
int index = atomicInteger.incrementAndGet();
System.out.println("create no " + index + " thread");
Thread t = new Thread(r, "Thread-" + index);
return t;
}
});
TestSync ts = new TestSync();
threadPool.execute(() -> {
try {
ts.doubleSync();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Print.sleep(1000);
threadPool.execute(() -> {
try {
ts.simpleSync();
} catch (Exception e) {
e.printStackTrace();
}
});
threadPool.shutdown();
}
}
class Print {
public static void sleep(long interval) {
System.out.println("sleep " + interval);
}
}
请注意,建议您在提交所有任务后调用接口 ExecutorService
的方法 shutdown()
。
这是我 运行 上述代码时的输出。
create no 1 thread
Producer trying to get LOCK_OBJECT lock
Producer get LOCK_OBJECT lock
sleep 1000
create no 2 thread
Consumer trying to get LOCK_OBJECT lock
sleep 3000
full!
如你所见,消费者没有获得锁。
Does
wait()
release all locks?
没有。它只会释放您调用 wait()
的对象的锁。
至于您的代码的行为...我们无法完全解释它,因为它缺少一个关键方法:Print
.
但是,您似乎正在使用 TestSync
的多个实例。那将意味着生产者和消费者线程对于各自的锁对象具有不同的对象......并且没有互斥。
使用多个线程池也是一个坏主意(浪费),尤其是动态创建和销毁它们。与一次性线程相比,线程池的主要优点是(重要的)线程创建被分摊。但是当你关闭(或“丢失”)一个线程池时,线程无论如何都会被丢弃......并且必须为“下一个”线程池再次创建。
(这不会影响您的示例的行为。但这是一个坏习惯......如果您在实际应用程序中这样做,它很容易咬到您。)
课程: 使用原始互斥锁和 wait/notify 编程需要格外小心。最好使用更高级别的并发原语......在可能的情况下。
1.It 最好继续执行一个 ExecutorService 实现(因为出于性能原因,我们始终保持有限数量的线程处于活动状态)
2.wait() 确实释放了单个对象的锁,但之后所有线程(考虑相同的优先级)都同样有可能获得锁