zoukankan      html  css  js  c++  java
  • java synchronized

      网上有许多关于synchronized关键字用法的文章,发现有些文章里介绍的用法和场景,这里我整理一下,通过实践,以一种有别于传统的写法介绍这个关键字的用法!用图文并茂的方式展示出来,希望大家理解起来更加简单易懂。本人知识有限,不足或错误的地方,欢迎指正,谢谢。

    准备个实际测试用的例子

    public class TestProgram extends Thread {
        
        static int j = 0;
        
        public static synchronized void testA(){
            j++;
            System.out.println(Thread.currentThread().getName() + ": " + j);
        }
        
        public synchronized void testB(){
            j++;
            System.out.println(Thread.currentThread().getName() + ": " + j);
        }
        
        public void testC(){
            System.out.println("into testC...");
            synchronized (this) {
                j++;
                System.out.println(Thread.currentThread().getName() + ": " + j);
            }
        }
       
    
        @Override
        public void run() {
            testA();
            testB();
            testC();
        }


    这就是这个例子的所有代码,代码简单。这里简短介绍一下:

      总共有三个测试方法,分别是testA、testB和testC。testA方法是一个加了synchronized关键字和static关键字的方法,testB是只加了synchronized关键字的方法,testC是代码块中包含了synchronized块的方法,这里分别用两种模拟环境测试这三个方法的不同,用来区分三个方法在不同场景下的不同!

    首先是测试环境(两个线程跑同一个program,我在这里只创建了一个TestProgram实例)

    同一实例下测试

    public static void main(String[] args) {
        TestProgram program = new TestProgram();
        Thread t = new Thread(program);
        Thread t2 = new Thread(program);
        t.start();
        t2.start();
    }

    测试testA()

    这里我用两个线程去测试,通过start()调用run()方法,我在testA()方法里打了个断点,然后两个线程跑起来,我们看结果

    我们在debug模式下,用多线程调试看结果,可以看到生成了Thread-1和Thread-2两个线程,在红色标记的代码中,可以看到Thread-1进入了testA()方法,而Thread-2则没有进入到testA()方法,这说明synchronized起到了同步作用。

    接着我让线程Thread-1跑完testA()方法后,Thread-2方法就直接被激活了,直接进入testA()方法,同步有效了。

    得到第一个结论,在同一个实例下,synchronized关键字是对static方法起到同步作用的。

    当Thread-1和Thread-2都跑完testA()方法后输出结果:

    Thread-1: 1
    Thread-2: 2

    为什么这个结论前面要加一个同一个实例?后面会看到,不在同一个实例下的多线程,synchronized关键效果不一样!

    接下来是进入testB()方法

    当Thread-1进入testB()方法时,看Thread-2线程进入了一种叫stepping的模式(类似于等待),在进入这个等待的过程中,如果我们将Thread-1线程跑完testB()方法,那么Thread-2的状态将由stepping改成suspended。简单的说就是当一个线程进入testB()时,其他线程都在等这个线程跑完。

    在这里发现synchronized方法也起到了同步的效果。

    再看测试testC()方法的效果

     我们可以看到,两个线程都进入到了testC()方法,而且两个线程的状态都是suspended。接下来,当线程Thread-1进入到synchronized代码块中,看结果

    可以看到当线程Thread-1进入代码块后,Thread-2再进入这个代码块,状态就变成了stepping等待的情况了。说明这里synchronized方式同步有效。

    最后执行testC()方法后的结果是:

    into testC...
    into testC...
    Thread-1: 5
    Thread-2: 6

    以上就是在同一个实例下跑出来的结果。但如果是这种情况下,情况就不同了,这也是我们经常遇到的问题,有时候感觉怎么与以前的理论相驳,接着分析

    不同实例下的测试

    public static void main(String[] args) {
        TestProgram program = new TestProgram();
        TestProgram program2 = new TestProgram();
        Thread t = new Thread(program);
        Thread t2 = new Thread(program2);
        t.start();
        t2.start();
    }

    换了两行代码,在两个相同的TestProgram中,创建两个对象,与上面的写法差异在两个线程跑各自的实例,这个时候synchronized的作用效果就不太一样了

    首先是testA()方法

    测试的结果是

    Thread-3: 1
    Thread-2: 2

    这个结果和开始测试的结果一样,说明在这里synchronized起到了同步效果!

    测试testB()

    这里结果就和上面测试testB()效果就不一样了,我们看效果

    从图中可以看到,两个线程都同时进入了testB()方法中,也就是synchronized关键字没起到同步两个线程的作用

    这里得出一个结论:两个不同的实例,在不同的线程环境下,synchronized并不能实现同步效果,当然,static方法除外

    后面的testC()方法也一样,看看效果

    两个线程都同时进入了第22行代码,就是同时在synchronized块中,说明这个synchronized代码块没有起到同步的效果。

    综合以上所诉,我得出一个这样的结论:

    如果多线程是对同一个对象的引用,那么synchronized关键字在所有的情况下都有同步的效果,如果多线程是对同一个对象的不同引用(创建了多个对象),除了static方法上面加的synchronized方法有同步引用的效果外,其他的synchronized(包括synchronized代码块)将没有同步的效果。

    至于为什么static方法上加synchronized方法,在不同的场景下都有效,原因是:被static修饰的成员变量和成员方法独立于该类的任何对象,static方法不属于类创建的引用,所以无论创建了多少个对象,对于static方法而言,都跟它没关系。

    ps:synchronized(this)这个this就是指对象的引用,这里指我当前线程的对象引用。

    我的疑问:为什么创建一个对象调试的时候,是Thread-1和Thread-2,而我创建两个对象调试的时候却是Thread-2和Thread-3?

  • 相关阅读:
    网易编程题——小易喜欢的单词
    Effective C++ 条款12:复制对象时勿忘其每一个成分
    Effective C++ 条款11:在operator=中处理"自我赋值"
    STM32-通用定时器基本定时功能
    GPIO_Mode
    STM32的ADC编程方法
    STM32的ADC采样与多通道ADC采样
    网络子系统
    linux网络子系统内核分析
    Linux 中高效编写 Bash 脚本的 10 个技巧
  • 原文地址:https://www.cnblogs.com/wxwall/p/3776414.html
Copyright © 2011-2022 走看看