• synchronized的四种作用域以及不能被继承解析


    synchronizedjava中用于同步的关键字,其典型的作用域如下所示.

    1 对象锁

    
    @Slf4j
    public class SynchronizedExample1 {
    
        private final int loopNum = 20;
    
        // 修饰一个代码块
        private void test1(int j) {
            synchronized (this) {
                for (int i = 0; i < loopNum; i++) {
                    log.info("test1 {} - {}", j, i);
                }
            }
        }
    
        // 修饰一个方法
        private synchronized void test2(int num) {
            for (int i = 0; i < loopNum; i++) {
                log.info("test2 {} - {}", num, i);
            }
        }
    
        public static void main(String[] args) {
            SynchronizedExample1 example1 = new SynchronizedExample1();
            SynchronizedExample1 example2 = new SynchronizedExample1();
            ExecutorService executorService = Executors.newCachedThreadPool();
    
            executorService.execute(() -> {
                example1.test2(1);
            });
            executorService.execute(() -> {
                example2.test2(2);
            });
            executorService.shutdown();
        }
    }
    

    1.1 代码块修饰(对象)

    此时,synchronized用于保证test1函数中的被synchronized大括号包裹的代码同步执行.
    synchronized作用的对象为SynchronizedExample1的对象实例,例如main函数中的example1以及example2.

    Tips:
    1.example1若在多个线程中被调用,其输出顺序将保证同步,按照1,2,3...19,20的顺序执行.
    2.若example1example2均在多个线程中执行,则test1...之间保持同步输出,test2...之间保持同步输出,但是test1...test2...之间输出不保证顺序.

    1.2 非静态函数修饰

    synchronized添加于test2函数声明中,其作用类似于1.1中的代码块修饰,区别点仅仅在于其同步代码块扩充至整个函数(test2).

    2. 类锁

    @Slf4j
    public class SynchronizedExample2 {
    
        private static final int loopNum = 20;
    
        // 修饰一个类
        private static void test1(int j) {
            synchronized (SynchronizedExample2.class) {
                for (int i = 0; i < loopNum; i++) {
                    log.info("test1 {} - {}", j, i);
                }
            }
        }
    
        // 修饰一个静态方法
        private static synchronized void test2(int j) {
            for (int i = 0; i < loopNum; i++) {
                log.info("test2 {} - {}", j, i);
            }
        }
    
        public static void main(String[] args) {
            SynchronizedExample2 example1 = new SynchronizedExample2();
            SynchronizedExample2 example2 = new SynchronizedExample2();
            ExecutorService executorService = Executors.newCachedThreadPool();
            executorService.execute(() -> {
                example1.test1(1);
            });
            executorService.execute(() -> {
                example2.test1(2);
            });
        }
    }
    

    2.1 代码块修饰(类)

    1.1中区别在于,synchronized函数修饰的是SynchronizedExample2类.
    SynchronizedExample2对象,诸如example1或者example2在任意多的线程中调用test1函数,其输出顺序均会被保证(1,2,3,4...19,20).

    2.2 静态函数修饰

    功能与2.1类似,均是对对象加锁,确保多个类对象调用函数时保持顺序.

    Tips:
    示例中,因为类上加锁的原因,test1test2对象保持顺序执行,不会出现test1...test2...交叉出现的现象.

    3 synchronized不能被继承

    需要注意,若synchronized修饰于函数中,如1.2以及2.2,若有类继承于SynchronizedExample1或者SynchronizedExample1,子类对象调用test2不同步.

    原因:synchronized非函数签名,因此无法被继承,所以无法保证子类调用同步.

    PS:
    如果您觉得我的文章对您有帮助,可以扫码领取下红包,谢谢!

  • 相关阅读:
    给Apache增加SSI支持(shtml的奥秘)
    Raphael实现商品来源去向图
    有趣的居中方式
    oc-基本语法
    APMServ 配置记录
    解决Mac Chrome打开HTTPS证书错误问题
    JavaScript生成GUID的算法
    Backbone模型
    利用apply和arguments复用方法
    软件复用的几种方式
  • 原文地址:https://www.cnblogs.com/jason1990/p/10211640.html
Copyright © 2020-2023  润新知