Я хотел проверить своими глазами разницу между сном и ожиданием.
Ожидание может быть выполнено только в синхронизированном блоке, поскольку оно освобождает право собственности на блокировку монитора. В то время как сон не связан с блокировкой монитора, и поток, который уже является владельцем блокировки монитора, не должен терять свое владение, если он находится в спящем режиме.
Для этого я сделал тест:
Шаги:
- Запущен поток, который ожидает в синхронизированном блоке 5 секунд.
- Подождал 3 секунды и запустил другой поток, который получает блокировку монитора (потому что Thread-A ожидает) и просто спит в течение 5 секунд, удерживая блокировку монитора.
Ожидаемый результат: Thread-A повторно получит блокировку только через 8 секунд, когда Thread-B, наконец, освободит блокировку монитора, выйдя из блока синхронизации.
Фактический результат. Thread - A получает блокировку монитора через 5 секунд.
Может ли кто-нибудь объяснить мне, что здесь произошло?
public static void main(String[] args) {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("r1 before synch block");
synchronized (this) {
System.out.println("r1 entered synch block");
try {
wait(5000);
System.out.println("r1 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Runnable r2 = new Runnable() {
@Override
public void run() {
System.out.println("r2 before synch block");
synchronized (this) {
System.out.println("r2 entered synch block");
try {
Thread.currentThread();
Thread.sleep(5000);
//wait(5000);
System.out.println("r2 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
try {
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
Thread.currentThread();
Thread.sleep(3000);
t2.start();
t1.join();
t2.join();
System.out.println(Thread.currentThread().getName() + " Finished joining");
} catch (Exception e) {
e.printStackTrace();
}
}
РЕДАКТИРОВАТЬ:
Хорошо, я понимаю свою ошибку - я жду этого - r1/r2, а не того же объекта.
Теперь я изменил его, и оба приобретают один и тот же объект - экземпляр класса Main. 1. r1 получает право собственности на блокировку монитора Main.this 2. r1 освобождает ее. 3. Когда r1 пытается повторно получить его, я получаю исключение:
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at Main$1.run(Main.java:28)
at java.lang.Thread.run(Unknown Source)
on synchronized (Main.this)
В чем проблема?
public static void main(String[] args) {
Main main = new Main();
main.test();
}
public void test() {
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("r1 before synch block");
synchronized (Main.this) {
System.out.println("r1 entered synch block");
try {
wait(5000);
System.out.println("r1 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Runnable r2 = new Runnable() {
@Override
public void run() {
System.out.println("r2 before synch block");
synchronized (Main.this) {
System.out.println("r2 entered synch block");
try {
Thread.currentThread();
Thread.sleep(5000);
//wait(5000);
System.out.println("r2 finished waiting");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
try {
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
Thread.currentThread();
Thread.sleep(3000);
t2.start();
t1.join();
t2.join();
System.out.println(Thread.currentThread().getName() + " Finished joining");
} catch (Exception e) {
e.printStackTrace();
}
}