首页 > 编程语言 >探索 java 中的各种锁

探索 java 中的各种锁

时间:2024-10-03 16:11:44浏览次数:7  
标签:各种 java String 探索 lock value key class

Java 8+

-

 

序章

一直听说 java 的各种锁、(线程)同步机制,一直没有深入探索。

最近多看了几篇博文,算是理解的比较深入一些了,特写本文做个记录。ben发布于博客园

 

锁是什么?

一种用于 多个线程运行时协调的机制。

作用如下:ben发布于博客园

1、用于多线程之间同步,比如,执行顺序先后。

2、确保共享数据安全——堆内存数据、方法区数据、类的变量(static)、实例的变量。

 

隐式锁 vs 显式锁

1、synchronized 是我了解到的 唯一的 隐式锁,由 JVM 自行实现。

2、其它的为 显式锁,比如,interface Lock、interface ReadWriteLock、class StampedLock 及其实现类。

class ReentrantLock 实现了 interface Lock。ben发布于博客园

 

synchronized

java 关键字。由JVM实现锁机制。

和 class Object 的 wait()/notify()/notifyAll() 配合使用。

 

特性:

可重入锁。非公平锁。独享锁。悲观锁。

插个翻译:Reentrant lock. Unfair locks. Exclusive locks. Pessimistic locks.

 

随着 JVM 的发展,其锁机制也在逐步变化。ben发布于博客园

偏向锁、轻量级锁、重量级锁、锁膨胀 等概念都和它有关,这些概念 还涉及 synchronized 底层实现用到的 Java对象头——Monitor。

插个翻译:Biased locks, lightweight locks, heavyweight locks, lock expansion

参考资料:The Java® Virtual Machine Specification: Java SE 8 Edition (pdf 文档可以去 Java官网下载)

The Java® Language Specification: Java SE 8 Edition

修饰 类方法(static),使用 Class 对象 关联的 monitor。

修饰 实例方法,使用 实例 this 对象 关联的 monitor。ben发布于博客园

当然,还可以锁定代码块。在 14.19 The synchronized Statement 中 有介绍:

 

interface Lock

方法定义:

实现类:

最出名的就是下面提到的 class ReentrantLock 。

 

class ReentrantLock

实现了 interface Lock。

底层使用 abstract class AbstractQueuedSynchronizer(#重点) 实现。

 

特性:

可重入锁。默认非公平锁,可以 初始化为 公平锁。独享锁。悲观锁。

类里面的 NonfairSync 为 非公平锁实现,而 FairSync 为公平锁。

 

单独使用(lock(), unlock()等),可以 保证 多线程时 共享数据安全。

结合 interface Condition 使用,可以 控制 多线程执行流程。

 

interface Condition

结构:

await() 类似于 Object 的 wait(),执行后,线程进入 阻塞状态。

signal()/signalAll() 类似于 Object 的 notify()/notify()All,唤醒阻塞的线程——一个或所有。

 

interface ReadWriteLock

适用于 读多写少 的场景。

提供了两个函数:

 

class ReentrantReadWriteLock

interface ReadWriteLock 的实现类。

底层使用 abstract class AbstractQueuedSynchronizer(#重点) 实现,内部类 Sync。

上面的内部类 ReadLock 和 WriteLock 都是实现了 Lock 接口的:

public static class ReadLock implements Lock, java.io.Serializable{
    private final Sync sync;
}

public static class WriteLock implements Lock, java.io.Serializable {
    private final Sync sync;
}

类里面的 sync 属性是实现 锁机制的关键。

 

特性:

读锁 是 共享式,写锁 是 独享锁(排他锁)。可重入锁。

 

示例程序(通义千问):

ReadWriteLockExample.java
 // *** 来自 通义千问 ***
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.HashMap;
import java.util.Map;

public class ReadWriteLockExample {

    private final Map<String, String> map = new HashMap<>();
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    private final ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
    private final ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();

    public String get(String key) {
        readLock.lock();
        try {
            return map.get(key);
        } finally {
            readLock.unlock();
        }
    }

    public void put(String key, String value) {
        writeLock.lock();
        try {
            map.put(key, value);
        } finally {
            writeLock.unlock();
        }
    }

    public void remove(String key) {
        writeLock.lock();
        try {
            map.remove(key);
        } finally {
            writeLock.unlock();
        }
    }

    public static void main(String[] args) {
        ReadWriteLockExample example = new ReadWriteLockExample();

        // 创建多个读线程
        for (int i = 0; i < 5; i++) {
            final int threadId = i;
            new Thread(() -> {
                for (int j = 0; j < 10; j++) {
                    String value = example.get("key" + (j % 5));
                    System.out.println("Reader " + threadId + ": key" + (j % 5) + " = " + value);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "Reader-" + i).start();
        }

        // 创建一个写线程
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                example.put("key" + i, "value" + i);
                System.out.println("Writer: Put key" + i + " = value" + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Writer").start();
    }
}

程序说明:

 

class StampedLock

Since: 1.8,Java 8 才开始有的。

参考资料#2 提供了足够多的信息。

适用于 读操作远远大于写操作 的场景——更胜于 前面的 interface ReadWriteLock。

 

特性:

乐观读锁。

 

类:

Node 类:

 

示例程序(通义千问):

StampedLockExample.java
// 来自 通义千问

import java.util.concurrent.locks.StampedLock;
import java.util.HashMap;
import java.util.Map;

public class StampedLockExample {

    private final Map<String, String> map = new HashMap<>();
    private final StampedLock lock = new StampedLock();

    public String getOptimistic(String key) {
        long stamp = lock.tryOptimisticRead();
        String value = map.get(key);
        // 检查是否有写操作发生
        if (!lock.validate(stamp)) {
            // 升级为悲观读锁
            stamp = lock.readLock();
            try {
                value = map.get(key);
            } finally {
                lock.unlockRead(stamp);
            }
        }
        return value;
    }

    public String get(String key) {
        long stamp = lock.readLock();
        try {
            return map.get(key);
        } finally {
            lock.unlockRead(stamp);
        }
    }

    public void put(String key, String value) {
        long stamp = lock.writeLock();
        try {
            map.put(key, value);
        } finally {
            lock.unlockWrite(stamp);
        }
    }

    public void remove(String key) {
        long stamp = lock.writeLock();
        try {
            map.remove(key);
        } finally {
            lock.unlockWrite(stamp);
        }
    }

    public static void main(String[] args) {
        StampedLockExample example = new StampedLockExample();

        // 创建多个读线程
        for (int i = 0; i < 5; i++) {
            final int threadId = i;
            new Thread(() -> {
                for (int j = 0; j < 10; j++) {
                    String value = example.getOptimistic("key" + (j % 5));
                    System.out.println("Reader " + threadId + ": key" + (j % 5) + " = " + value);
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }, "Reader-" + i).start();
        }

        // 创建一个写线程
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                example.put("key" + i, "value" + i);
                System.out.println("Writer: Put key" + i + " = value" + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "Writer").start();
    }
}

说明:

 

小结

探索 期间,遇到了 AbstractQueuedSynchronizer、Unsafe 等,还需要进一步探索(看更多博文呗)。

整个 java.util.concurrent.locks 包 下的内容:

 

疑问:

有了这些锁机制,为什么还需要 class CountDownLatch、class CyclicBarrier、class Semaphore 等呢?它们和 多线程开发 有什么关系?

还有就是 java.util.concurrent.atomic 下的东西。

 

---END---

 

本文链接:

https://www.cnblogs.com/luo630/p/18445669/java-locks-note

 

参考资料

1、java里的锁总结(synchronized隐式锁、Lock显式锁、volatile、CAS)
https://www.cnblogs.com/lifegoeson/p/13683785.html
posted @ 2020-09-17 10:38  Life_Goes_On

2、深入了解Java中的锁机制
2024-03-04
https://developer.aliyun.com/article/1449639

3、一文彻底搞懂面试中常问的各种“锁”
https://www.cnblogs.com/coding-night/p/10657892.html
posted on 2019-04-05 08:24  深夜里的程序猿

4、

 

ben发布于博客园

ben发布于博客园

 

标签:各种,java,String,探索,lock,value,key,class
From: https://www.cnblogs.com/luo630/p/18445669/java-locks-note

相关文章

  • Java内存区域与分配策略
    1.运行时数据区Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域有各自的用途,创建和以及销毁的时间,有的区域随着虚拟机进程的启动而一直存在,有的区域则是依赖用户线程的启动结束而建立和销毁。1.1程序计数器(线程私有)程序计数器(Pro......
  • Java毕业设计:基于Springboo汽车故障维修预约网站毕业设计源代码作品和开题报告
     博主介绍:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。所有项目都配有从入门到精通的基础知识视频课程,学习后应对毕业设计答辩。项目配有对应开发文档、开题报告、任务书、P......
  • Java数组
    数组数组概述数组是相同类型数据的有序集合数组声明创建首先必须声明数组变量,才能在程序中使用数组。dataType[]array//首选方法或dataTypearray[]//效果相同,但不是首选方法Java语言使用new操作符来创建数组dataType[]array=newdataType[arraySize];获取数......
  • 《Java 高级篇》八:新特性
    Author:ACatSmilingSince:2024-10-01Lambda表达式Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。Lambda表达式......
  • 《Java 高级篇》六:I/O 流
    Author:ACatSmilingSince:2024-10-01字符编码字符集Charset:也叫编码表。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。编码表的由来:计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个......
  • 《Java 高级篇》七:线程和线程池
    Author:ACatSmilingSince:2024-10-01程序、进程和线程程序(program):是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。进程(process):是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生、存在和消亡的过程——生......
  • Java多态性:面向对象编程的精髓
    目录1.什么是多态性?2.多态性的两种形式2.1 编译时多态(静态多态)2.2 运行时多态(动态多态)3.多态性的好处4.示例代码5.拓展知识5.1抽象类和接口5.2泛型5.3反射在软件开发的世界里,Java以其强大的面向对象编程(OOP)特性而闻名。今天,我们将深入探讨Java中的核心概......
  • 《Java 高级篇》四:反射
    Author:ACatSmilingSince:2024-10-01概述Reflection(反射)被视为动态语言的关键,反射机制允许程序在执行期借助于ReflectionAPI获取任何类的内部信息,并能直接操作任意对象的内部属性及方法。动态语言:是一类在运行时可以改变其结构的语言。例如新的函数、对象、甚至代码可......
  • Java方法
    方法方法的定义和使用方法包含于类或对象中在程序中被创建,在其他地方被引用首字母小写和驼峰原则命名一个方法值完成一个功能,这样利于我们后期扩展返回值类型修饰符返回值类型方法名(参数类型参数名){方法体return返回值}若无返回值就使用voidpublicstat......
  • 总结28个令人惊艳的JavaScript单行代码
    1.阶乘计算使用递归函数计算给定数字的阶乘。12constfactorial=n=>n===0?1:n*factorial(n-1);console.log(factorial(5));//输出120 2.判断一个变量是否为对象类型1constisObject=variable===Object(variable);......