Синхронизированный метод не работает, но синхронизированный блок работает, почему?

#java #multithreading #synchronization #synchronized

#Ява #многопоточность #синхронизация #синхронизировано

Вопрос:

 public class driver{   public static void main(String[] args) {  PrintNum firstObjectForThread = new PrintNum(0); // the argument is not used, ignore it  firstObjectForThread.startNewThread();   PrintNum secondObjectForThread = new PrintNum(0);  secondObjectForThread.startNewThread();  }  

Это класс, который вызывает драйвер:

 public class ClassName implements Runnable{  int variableForUpdate; private Thread t; private static ArrayListlt;Integergt; intArray;  public ClassName(int variableForUpdate) {  super();  this.intArray = new ArrayListlt;Integergt;();  this.variableForUpdate = variableForUpdate;  for (int i = 0; i lt; 30 ; i  ) {  this.intArray.add(i);  } }  @Override public void run() {  runThisWhenThreadStarts(); }   private synchronized void runThisWhenThreadStarts() {  System.out.println("Started");  for (int i = 0; i lt; 30; i  ) {  System.out.println(intArray.get(i));  } }  public void startNewThread() {  t = new Thread(this);  t.start(); }  }  

Если я использую синхронизацию блоков следующим образом, вывод синхронизируется:

 private void runThisWhenThreadStarts() {  synchronized (ClassName.class) {  System.out.println("Started");  for (int i = 0; i lt; 30; i  ) {  System.out.println(intArray.get(i));  }  } }  

Я устранял неполадки в течение многих часов и не могу понять… Кто-нибудь может пролить немного света, пожалуйста? Я также замечаю, что если я использую тот же объект для вызова startNewThread (), синхронизация будет работать. Но я не понимаю, почему.

 PrintNum firstObjectForThread = new PrintNum(0); // the argument is not used, ignore it  firstObjectForThread.startNewThread();  firstObjectForThread.startNewThread();  

Я хочу использовать два разных объекта из одного и того же класса вместо одного объекта, вызывающего метод дважды (описанный выше обходной путь).

I am able to use the synchronized methods in another program, with 2 different instances (get and put) :

 public class Hello extends Thread {  int x;  Coffee x1;  int threadno;   Hello(int x, Coffee x1) {  this.x = x;  threadno = x;  this.x1 = x1;  }   public void run() {  switch (x) {  case 0:  System.out.println("Start thread "   threadno   " Get");  break;  case 1:  System.out.println("Start thread "   threadno   " Put");  break;  }  ops();  System.out.println("Stopping thread "   threadno);   }   public void ops() {  x1.get();  }   public static void main(String[] args) {  Coffee c1 = new Coffee();  Hello get = new Hello(0, c1);  Hello put = new Hello(0, c1);  get.start();  put.start();   } }  

Привет класс позвонит в класс кофе:

 class Coffee {  boolean available = false; // indicating there nothing to get.  // waiting on each other.  int contents = 55;   public synchronized int get() {  System.out.println("Entering Get method "   contents);  for (int i = 0; i lt; 30; i  ) {  System.out.println(i);  }  return contents;  } }  

Ответ №1:

В первом примере метод получает блокировку экземпляра объекта, для которого вызывается метод. Блок этого не делает, вместо этого он получает блокировку класса.

Снятие блокировки с экземпляра не влияет на другой поток, это другой объект. Оба потока приобретают свою собственную блокировку, что бесполезно. Ни одному потоку ничего не мешает делать.

Блокировка класса означает, что оба потока пытаются получить одну и ту же блокировку. Чтобы блокировка работала, один и тот же замок должен использоваться обоими потоками.

Во втором примере объект Coffee совместно используется обоими потоками, и оба потока пытаются получить одинаковую блокировку объекта Coffee. Это означает, что второй поток, чтобы добраться до блокировки, должен блокироваться до тех пор, пока блокировка не будет снята первым потоком, успешная блокировка удерживает поток до завершения первого потока.

Чтобы понять, что синхронизировано, следите за тем, какие блокировки приобретаются.

Комментарии:

1. Спасибо. Я тоже так думал. Но у меня есть другая программа, которая действительно может использовать синхронизацию с 2 объектами одного класса, синхронизация будет работать. Ты знаешь почему? Я опубликовал код в своем вопросе.

2. @IHaveAQuestion: уже обновлено

3. Спасибо вам за быстрый ответ. Почему два объекта Hello совместно используют один и тот же объект Coffee? Когда создается экземпляр объекта Hello, он должен создать новый объект Coffee с помощью «Coffee c1 = новый кофе();»? отредактировано: А, понятно! Теперь все имеет смысл!