Потоковые и синхронизированные методы

#java #multithreading #synchronization

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

Вопрос:

У меня есть следующий код:

 public class MyThread extends Thread {
    private int i;
    public static int sum=0;
    public MyThread(int k){
      i=k;
    }




    public static void main(String[] args) throws InterruptedException{

       Thread t=new MyThread(1);
       Thread s=new MyThread(2);
       Thread p=new MyThread(3);
       t.start();
       s.start();       
    }


public synchronized void doSomething(){
    for(int i=0; i<100000; i  ){
        System.out.println(this.i);
    }

}

    @Override
    public void run() {
        doSomething();

    }
}
  

doSomething синхронизирован. почему вывод случайный?
Я предполагаю, что синхронизированный метод будет таким же, как синхронизированный блок, но вывод блока — sync, а метод — нет.

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

1. Что вы подразумеваете под «случайным»? Из кода видно, что у вас запущено 3 потока, каждому будет выделено процессорное время, и поэтому выходные данные будут чередоваться.

Ответ №1:

synchronized Ключевое слово там предотвращает чередование синхронизированных вызовов методов для одного и того же объекта. Это не предотвращает чередование вызовов методов для разных объектов. Поскольку у вас есть три разных объекта, три вызова могут выполняться одновременно.

Вам необходимо выполнить синхронизацию на одном объекте, который является общим для всех трех потоков.

Ответ №2:

Синхронизация методов выполняется только для вызовов одного и того же объекта. Вы создаете два разных объекта (два потока).

Ответ №3:

Блокировка, используемая synchronized методами, связана с экземпляром класса MyThread . Поскольку каждый поток имеет свой собственный экземпляр MyThread , каждый поток синхронизируется по своей собственной блокировке.

Если вы хотите синхронизировать все потоки, вы могли бы сделать что-то вроде:

 public class MyThread extends Thread {

    private static final Object sharedLock = new Object();

    public void doSomething() {
      synchronized(sharedLock) {
        for(int i=0; i<100000; i  ) {
          System.out.println(this.i);
        }
      }
    }
    ...
 }
  

Альтернативой является synchronize on MyThread.class , но я предпочитаю первый подход.

В комментариях вы говорите, что если вы измените свой код на использование synchronized(this) в doSomething , внезапно это сработает. Я почти уверен, что это не так. Возможно, это сработало случайно, но оно не будет работать постоянно и надежно.

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

1. но если я изменю его на synchronized (this) и помещу цикл внутрь, он действительно получит упорядоченные результаты, но синхронизация выполняется в экземпляре класса mythread