学习Java,使用synchronized关键字

911*_*boS 29 java synchronized

所以我正在测试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){}
       }
    };
}  
Run Code Online (Sandbox Code Playgroud)

当我运行它时,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  
Run Code Online (Sandbox Code Playgroud)

当我将方法更改countMe()为:

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

我得到这个输出:

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  
Run Code Online (Sandbox Code Playgroud)

虽然这让我清楚地了解了目的synchronized,但我想知道还有其他原因,我们可以使用synchronized.或者我在这里做了什么,是我们需要使用这个synchronized关键字的唯一原因?

谢谢.

编辑:我很困惑的另一件事是,在第一次输出为什么计数器在7之后变为3.对我来说似乎有点不可能,但每次尝试都会发生类似的结果,这是正常的吗?

vul*_*ino 26

两件事情:

首先,对同一对象的两个同步方法的调用不可能进行交错.当一个线程正在为对象执行同步方法时,所有其他线程调用同一对象的同步方法(暂停执行)直到第一个线程完成对象.

其次,当同步方法退出时,它会自动与同一对象的同步方法的任何后续调用建立先发生关系.这可以保证对所有线程都可以看到对象状态的更改.

同步方法启用了一种简单的策略来防止线程干扰和内存一致性错误:如果一个对象对多个线程可见,则对该对象变量的所有读取或写入都是通过同步方法完成的.(一个重要的例外:构造对象后无法修改的final字段,一旦构造了对象,就可以通过非同步方法安全地读取).

来源:http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html


Dav*_*d V 11

Vulkanino对你的主要问题给出了一个很好的答案,所以我只会在7之后解决你关于3打印的问题.

3可以在7之后打印,因为在语句中实际上有比Java代码更多的字节代码.

我会扩展它.

你打电话

System.out.println("Current Counter is: " + i);
Run Code Online (Sandbox Code Playgroud)

它出现在一行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
Run Code Online (Sandbox Code Playgroud)