• java EE初阶 — synchronized 关键字 - 监视器锁 monitor lock


    1.synchronized 的特性

    1.1 互斥

    synchronized 会起到互斥效果, 某个线程执行到某个对象的 synchronized 中时, 其他线程如果也执行到同一个对象 synchronized 就会阻塞等待

    • 进入 synchronized 修饰的代码块,相当于 加锁
    • 退出 synchronized 修饰的代码块,相当于 解锁


    可以粗略理解成,每个对象在内存中存储的时候,都存有一块内存表示当前的 “锁定” 状态(类似于厕
    所的 “有人/无人”).。
    如果当前是 “无人” 状态,那么就可以使用,使用时需要设为 “有人” 状态。
    如果当前是 “有人” 状态, 那么其他人无法使用,只能排队。

    阻塞等待:

    针对每一把锁,操作系统内部都维护了一个等待队列。当这个锁被某个线程占有的时候,其他线程尝试进行加锁, 就加不上了,就会阻塞等待, 一直等到之前的线程解锁之后,由操作系统唤醒一个新的线程, 再来获取到这个锁。

    1.2 可重入

    一个线程针对同一个对象,如果不会发生问题就叫可重入的,否则就叫不可重入的

    class Counter {
        public int count = 0;
    
        synchronized public void add() {
            synchronized(this) {
                count++;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    锁对象是 this ,只要有线程调用 add 方法,进入 add 方法的时候,
    在可以加锁成功的前提下,就会先加锁。紧接着又遇到了代码块,此时会再次尝试加锁。

    站在 锁对象的视角(this),他认为自己已经被其他的线程给占用了,
    那么这里的第二次加锁是不需要阻塞等待的。

    如果允许上述操作,这个锁就是可重入的;不允许就是不可重入的。
    如果是不可重入的,就会发生 死锁。

    上面演示的就是一个不可重入引起的死锁现象。



    下面演示的是可重入的情况。



    java 为了避免不小心出现闭锁现象,就把 synchronized 给设置成可重入的了。
    因此 java 中的 synchronized 是可重入锁。

    2.synchronized 使用示例

    修饰普通方法:

    public synchronized void add2() {
        count++;
    }
    
    • 1
    • 2
    • 3

    修饰静态方法:

    public synchronized static void add2() {
        count++;
    }
    
    • 1
    • 2
    • 3

    重点理解 synchronized 锁的意思。

    两个线程调试竞争一把锁才会发生阻塞等待,如果是两把锁就不会了。

    修饰代码块:

    synchronized public void add() {
        synchronized(this) {
            count++;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.Java 标准库中的线程安全类

    如果多个线程操作同一个集合类,就需要考虑到线程安全问题的事情。

    • ArrayList
    • LinkedList
    • HashMap
    • TreeMap
    • HashSet
    • TreeSet
    • StringBuilder

    这些类在没有线程安全问题的时候,放心使用。
    在有安全问题的时候,可以手动加锁使用。

    这些类有更多的选择空间。

    • Vector
    • HashTable
    • ConcurrentHashMap
    • StringBuffer

    这些类当中内置了 synchronized 加锁。相对于上面的类更安全。

    因为是强行加锁的,不管是需不需要,它都会加锁,而且加锁是有额外的时间开销的。
    因此它的选择空间变小了,是不推荐使用的。

    • String

    这个类虽然没有加锁,但是也是安全的,因为它不涉及修改。

  • 相关阅读:
    Python网络爬虫项目开发实战:怎么解决表单交互
    Keil MDK下如何设置非零初始化变量 - 基于Arm Compiler 6
    DaoWiki(基于Django)开发笔记 20231113-2
    Unity添加自定义菜单按钮
    【Linux网络】TCP协议
    【开发工具】【Valgrind】内存问题检测工具(valgrind)的使用
    一图了解es6常用数据迭代函数map,filter,fill,reduce
    【养成系】Linux常用命令
    如何利用OpenGL巧妙实现GPU仿真
    基于Django + Web + MySQL的智慧校园系统
  • 原文地址:https://blog.csdn.net/m0_63033419/article/details/128123317