• synchronized关键字


    关键字synchronized可以修饰方法或者以同步块的形式来进行使用,它主要确保多个线程在同一个时刻,只能有一个线程处于方法或者同步块中,它保证了线程对变量访问的可见性和排他性。

    锁的对象是什么

    对不熟悉多线程原理的人来说,很容易误解 synchronized 关键字:它通常加在所有的静态成员函数和非静态成员函数的前面,表面 看好像是“函数之间的互斥”,其实不是。synchronized关键字其实 是“给某个对象加了把锁”,这个锁究竟加在了什么对象上面?如下 面的代码所示,给函数f1()、f2()加上synchronized关键字。

    class A {
        public synchronized void f1() {
            log.info("f11");
        }
        public static synchronized void f2() {
            log.info("f2");
        }
    }
    

    等价于如下代码:

    class A {
        public void f1() {
            synchronized (this) {
                log.info("f1");
            }
        }
        public static void f2() {
            synchronized (A.class) {
                log.info("f2");
            }
        }
    }
    

    对于非静态成员函数,锁其实是加在对象a上面的;对于静态成员 函数,锁是加在A.class上面的。当然,class本身也是对象。

    这间接回答了关于 synchronized 的常见问题:一个静态成员函 数和一个非静态成员函数,都加了synchronized关键字,分别被两个 线程调用,它们是否互斥?很显然,因为是两把不同的锁,所以不会 互斥。

    synchronized同步的对象可以是任意对象,任意对象都有一个锁和等待队列,或者说,任何对象都可以作为锁对象。比如,f1()的等价代码还可以是。

    class A {
        private Object lock = new Object();
        public void f1() {
            synchronized (lock) {
                log.info("f1");
            }
        }
    }
    

    锁的本质是什么

    无论使用什么编程语言,只要是多线程的,就一定会涉及锁。既 然锁如此常见,那么锁的本质到底是什么呢?

    如图1-2所示,多个线程要访问同一个资源。线程就是一段段运行 的代码;资源就是一个变量、一个对象或一个文件等;而锁就是要实 现线程对资源的访问控制,保证同一时间只能有一个线程去访问某一 个资源。打个比方,线程就是一个个游客,资源就是一个待参观的房 子。这个房子同一时间只允许一个游客进去参观,当一个人出来后下 一个人才能进去。而锁,就是这个房子门口的守卫。

     从程序角度来看,锁其实就是一个“对象”,这个对象要完成以 下几件事情:

    (1)这个对象内部得有一个标志位(state变量),记录自己有 没有被某个线程占用(也就是记录当前有没有游客已经进入了房 子)。最简单的情况是这个state有0、1两个取值,0表示没有线程占 用这个锁,1表示有某个线程占用了这个锁。

    (2)如果这个对象被某个线程占用,它得记录这个线程的thread ID,知道自己是被哪个线程占用了(也就是记录现在是谁在房子里 面)。

    (3)这个对象还得维护一个thread id list,记录其他所有阻塞 的、等待拿这个锁的线程(也就是记录所有在外边等待的游客)。在 当前线程释放锁之后(也就是把state从1改回0),从这个thread id list里面取一个线程唤醒。

    既然锁是一个“对象”,要访问的共享资源本身也是一个对象, 例如前面的对象 a,这两个对象可以合成一个对象。代码就变成synch ronized(this){…},我们要访问的共享资源是对象a,锁也是加在 对象a上面的。当然,也可以另外新建一个对象,代码变成synchroniz ed(obj1){…}。这个时候,访问的共享资源是对象a,而锁是加在新 建的对象obj1上面的。

    资源和锁合二为一,使得在Java里面,synchronized关键字可以 加在任何对象的成员上面。这意味着,这个对象既是共享资源,同时 也具备“锁”的功能!

    下面来看 Java 是如何做到让任何一个对象都具备“锁”的功能 的,这也就是 synchronized的实现原理。

    synchronized实现原理

    答案在Java的对象头里。在对象头里,有一块数据叫Mark Word。 在64位机器上,Mark Word是8字节(64位)的,这64位中有2个重要字 段:锁标志位和占用该锁的thread ID。因为不同版本的JVM实现,对 象头的数据结构会有各种差异

    参考: Java并发实现原理:JDK源码剖析 1.3 synchronized关键字

      Java编程的逻辑 15.2 理解synchronized

      Java并发编程的艺术 4.3.1 volatile和synchronized关键字

  • 相关阅读:
    MySQL学习(一) 概述
    Spring Tool Suite生成默认的MVC项目的配置文件问题
    [国家集训队]排队
    「PKUSC2018」最大前缀和
    「PKUSC2018」真实排名
    Min-Max容斥 & FMT
    SPOJ-CLFLARR 题解
    FFT详解
    CF Round#446 改题
    [CF1131D]Gourmet Choice 题解
  • 原文地址:https://www.cnblogs.com/ooo0/p/15827187.html
Copyright © 2020-2023  润新知