Синхронизированные два потока не работают синхронизировано

#java #multithreading #synchronized

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

Вопрос:

рассмотрим следующий код:

 public class Main {

    public static void main(String[] args){
        MyObject obj = new MyObject();
        Thread1 t1 = new Thread1(100,'#',obj);
        Thread1 t2 = new Thread1(100,'*',obj);

        t1.start();
        t2.start();
    }
}
  

 public class Thread1 extends Thread {

    int myNum;
    char myChar;
    MyObject myObj;

    public Thread1(int num, char c, MyObject obj){
        myNum = num;
        myChar = c;
        myObj = obj;
    }

    public synchronized void run(){
        for(int i = 1; i<myNum; i  ){
            if((i%10)==0)
                System.out.println("");
            System.out.print(myChar);
        }
    }

}
  

Класс MyObject является пустым классом без каких-либо пробелов.
Мой вопрос в том, почему синхронизированный не работает , и я печатаю ‘#’ и ‘
‘ одновременно и в случайном порядке, а не один за другим?

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

1. «не работает» — это не описание проблемы. Опишите, что он должен делать.

2. Это два разных потока, выполняющих свой run() метод независимо. sychronized() не укладывается в картину.

3. Рохит Джейн почему синхронизированный не входит в картину? Я установил этот метод запуска для синхронизации

Ответ №1:

Синхронизация блокирует монитор объекта. В вашем случае выполняется синхронизация с каждым из объектов потоков, то есть поток A блокируется на мониторе потоков A, а поток B блокируется на мониторе потока B. Таким образом, они не взаимодействуют.

Я думаю, что вы имели в виду следующее для метода run():

 public void run(){
  synchronized (myObj) {
    for(int i = 1; i<myNum; i  ){
        if((i%10)==0)
            System.out.println("");
        System.out.print(myChar);
    }
  }
}
  

Если это действительно было вашим предполагаемым использованием для myObj, то я бы также предложил следующее изменение; поскольку это поможет сделать код более читаемым.

Изменить:

 MyObject myObj;
  

Для:

 private final MyObject lock;
  

ОТРЕДАКТИРУЙТЕ альтернативный подход, который не блокирует myObj, а вместо этого экземпляр класса Thread1.

 public void run(){
    doJob();
}

private static synchronized void doJob() {
    for(int i = 1; i<myNum; i  ){
        if((i%10)==0)
            System.out.println("");
        System.out.print(myChar);
    }
}
  

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

1. Я понимаю вашу точку зрения, но если я хочу получить тот же результат, только установив для всего метода значение synchronized и не использовать synchronized (myObj), как я могу это сделать? Спасибо

2. Это означало бы, что оба потока совместно использовали один и тот же экземпляр объекта Thread. Этого не может быть. Есть другие игры, в которые вы могли бы поиграть, чтобы получить метод в общем экземпляре, например, добавить синхронизированный метод в MyObject или использовать статический метод. Статические методы, которые синхронизированы, блокируют объект класса, который будет использоваться совместно двумя потоками. Однако метод run() не может быть объявлен статическим, поэтому вам снова придется перепрыгнуть через пару обручей, чтобы заставить что-то подобное работать.

Ответ №2:

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

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

        MyObject obj = new MyObject();
        Thread1 t1 = new Thread1(50,'#',obj);
        Thread1 t2 = new Thread1(50,'*',obj);

        Thread[] threads = {t1, t2}; 


        start(threads);


    }


    public synchronized static void start(Thread[] threads) throws InterruptedException{

        synchronized(threads){
            for(int i=0; i < threads.length; i  )   {
                threads[i].start();
                threads[i].join();
            }
        }

    }
}
  

ВЫВОД:

 #########
##########
##########
##########
##########*********
**********
**********
**********
**********