Я написал небольшой блок кода, чтобы понять понятия synchronized
блоков:
public class ObjectLevelSynchronized {
public void run() {
synchronized(this) {
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(100);
System.out.println(Thread.currentThread().getName() + " Finished.");
}catch(Exception e) {
}
}
}
public static void main(String[] args) throws Exception {
final ObjectLevelSynchronized c = new ObjectLevelSynchronized();
final ObjectLevelSynchronized c1 = new ObjectLevelSynchronized();
Thread t = new Thread(new Runnable() {
public void run() {
c.run();
c.run();
}
}, "MyThread1");
Thread t1 = new Thread(new Runnable() {
public void run() {
c1.run();
c1.run();
}
}, "MyThread2");
t.start();
t1.start();
}
}
Только один поток может выполняться внутри блока кода Java, синхронизированного на одном объекте монитора, я вызываю метод run
из двух разных потоков и двух разных экземпляров.
Ожидаемый результат:
MyThread1
MyThread2
MyThread1 Finished
MyThread2 Finished
MyThread1
MyThread2
MyThread1 Finished
MyThread2 Finished
Фактический результат
MyThread1
MyThread1 Finished.
MyThread1
MyThread1 Finished.
MyThread2
MyThread2 Finished.
MyThread2
MyThread2 Finished.
Почему synchronized
блок заблокировал код для двух разных объектов?
у вас есть два разных замка.
вы используете synchronized(this)
и вы создаете два объекта
final ClassLevelSynchronized c = new ClassLevelSynchronized();
final ClassLevelSynchronized c1 = new ClassLevelSynchronized();
поэтому c и c1 - ваши блокировки, и синхронизация просматривает эти блокировки. вы должны использовать тот же объект для синхронизации блока. Самый простой способ для вас:
private static Object lock = new Object();
и использовать его в синхронизированном
synchronized(lock)
или, для вашего вывода, это тоже должно работать.
public static void main(String[] args) throws Exception {
final ObjectLevelSynchronized c = new ObjectLevelSynchronized();
final ObjectLevelSynchronized c1 = new ObjectLevelSynchronized();
final Object lock = new Object();
Thread t = new Thread(new Runnable() {
public void run() {
synchronized (lock) {
c.run();
c.run();
}
}
}, "MyThread1");
Thread t1 = new Thread(new Runnable() {
public void run() {
synchronized (lock) {
c1.run();
c1.run();
}
}
}, "MyThread2");
t.start();
t1.start();
}
Мой результат следующий, как вы ожидали:
MyThread2
MyThread1
MyThread2 Finished.
MyThread2
MyThread1 Finished.
MyThread1
MyThread2 Finished.
MyThread1 Finished.
При тестировании многопоточных программ всегда выполняйте несколько прогонов, потому что вывод не всегда одинаковый, потому что порядок выполнения может отличаться.
Предполагая, что тип ObjectLevelSynchronized
, на основе кода, который вы поделили, не обязательно, чтобы программа ObjectLevelSynchronized
результат так же, как вы делились, так как no mechanism
для связи между двумя экземплярами созданных вами объектов и выполняться в разных потоки. Во-вторых, порядок инструкций Sysout основан исключительно на усмотрении JVM/OS, т.е. Один из T1 и T2 может работать первым. Поэтому для того, чтобы распечатать то, как вы ожидали, вам нужно связаться с другими экземплярами, кто должен печатать первые или простые слова, для которых требуется блокировка для совместного использования между этими двумя объектами, которые выполняются в потоках