学习Java,使用同步关键字

2022-09-01 12:03:10

所以我用关键字测试。以下是我尝试过的一个示例: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  

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

谢谢。

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


答案 1

两件事:

首先,在同一对象上两次调用同步方法不可能交错。当一个线程为对象执行同步方法时,调用同一对象块的同步方法的所有其他线程(挂起执行),直到第一个线程完成该对象。

其次,当同步方法退出时,它会自动与同一对象的同步方法的任何后续调用建立“发生之前”关系。这保证了对对象状态的更改对所有线程都可见。

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

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


答案 2

Vulkanino对你的主要问题给出了很好的回答,所以我只回答你关于7之后3次印刷的问题。

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

推荐