Изучение Java, использование синхронизированного ключевого слова - PullRequest
28 голосов
/ 08 февраля 2012

, поэтому я тестировал с ключевым словом 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?

Спасибо.

РЕДАКТИРОВАТЬ: Еще одна вещь, с которой я путаюсь, заключается в том, что в первом выводе счетчик перешел на 3 после 7. Это кажется мне немного невозможным, но подобные результаты случаются каждый раз, когда я пытаюсь, это нормально?

Ответы [ 2 ]

26 голосов
/ 08 февраля 2012

Две вещи:

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

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

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

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

11 голосов
/ 08 февраля 2012

Вулканино дал хороший ответ на ваш главный вопрос, поэтому я отвечу на ваш вопрос только о 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...