Подтвердить что ты не робот

Изучение Java, использование синхронизированного ключевого слова

поэтому я тестировал ключевое слово synchronized. Вот пример, который я пробовал:

public class MyTest {
    static int i = 0;
    public static void main(String[] args) {
        new Thread(t1).start();
        new Thread(t2).start();
    }

    private static void countMe(String name){
        i++;
        System.out.println("Current Counter is: " + i + ", updated by: " + name);
    }

    private static Runnable t1 = new Runnable() {
        public void run() {
            try{
                for(int i=0; i<5; i++){
                    countMe("t1");
                }
            } catch (Exception e){}

        }
    };

    private static Runnable t2 = new Runnable() {
        public void run() {
            try{
                for(int i=0; i<5; i++){
                    countMe("t2");
                }
            } catch (Exception e){}
       }
    };
}  

Когда я запускаю его, вывод вызова метода countMe() из двух потоков генерирует этот вывод:

Current Counter is: 1
Current Counter is: 2
Current Counter is: 4
Current Counter is: 5
Current Counter is: 6
Current Counter is: 7
Current Counter is: 3
Current Counter is: 8
Current Counter is: 9
Current Counter is: 10  

И когда я меняю метод countMe() на:

private synchronized static void countMe(){
        i++;
        System.out.println("Current Counter is: " + i);
}  

Я получаю этот вывод:

Current Counter is: 1
Current Counter is: 2
Current Counter is: 3
Current Counter is: 4
Current Counter is: 5
Current Counter is: 6
Current Counter is: 7
Current Counter is: 8
Current Counter is: 9
Current Counter is: 10  

Хотя это дает мне ясное понимание цели synchronized, я хочу знать, есть ли другая причина, которую мы можем использовать synchronized. Или то, что я сделал здесь, является единственным сменой, почему нам нужно использовать это ключевое слово synchronized?

Спасибо.

EDIT: Еще одна вещь, с которой я запутался, заключается в том, что в первом выпуске, почему счетчик пошел на 3 после 7. Мне кажется, это немного невозможно, но подобные результаты случаются каждый раз, когда я пытаюсь, является ли это нормальным?

4b9b3361

Ответ 1

Две вещи:

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

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

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

источник: http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

Ответ 2

Вулканино дал хороший ответ на ваш главный вопрос, поэтому я остановлюсь только на вашем вопросе о печати 3 после 7.

3 могут печатать после 7, потому что на самом деле в ваших операторах гораздо больше байтового кода, чем код Java.

Я расскажу об этом.

Вы вызываете

System.out.println("Current Counter is: " + i);

и это происходит в одной строке кода Java, но на самом деле происходит то, что создается строка, и затем эта строка передается println. Метод println сам должен выполнить небольшую обработку, прежде чем он действительно напишет строку на консоль.

Понятно, что происходит следующее.

String printlnString = "Current Counter is: 3"
--> maybe the other thread executes here
System.out.println(printlnString);
--> or maybe the other thread executes here
i is now equal to 7 and the console has "Current Counter is: 7"
println writes "Current Counter is: 3" to console