搜索
首页Javajava教程Java中的锁是什么?Java中锁的详细介绍

本篇文章给大家带来的内容是关于Java中的锁是什么?Java中锁的详细介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

1.简介

JAVA中实现加锁是通过Synchronized关键字以及java.util.concurrent包下的相关类。

Java提供的用于实现加锁的相关API:

 index.png

Lock提供了比使用Synchronized同步方法和同步语句块更广泛的锁定操作。

2.java.util.concurrent包

Lock接口

//试图获取锁.
void lock() 
 
//如果当前线程未被中断,则获取锁.
void lockInterruptibly()
         
//返回绑定到此 Lock 实例的新 Condition 实例.
Condition newCondition()
          
//仅在调用时锁为空闲状态才获取该锁.
boolean tryLock()
          
//如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁.
boolean tryLock(long time, TimeUnit unit)
          
//试图释放锁.
void unlock()

ReentranLock类

构造方法

//创建一个 ReentrantLock 的实例.
ReentrantLock()          
//创建一个具有给定公平策略的 ReentrantLock实例.
ReentrantLock(boolean fair)

公平锁:多线程按照申请锁的顺序获取锁。

非公平锁:多线程并非按照申请锁的顺序获取锁,即先申请锁的线程不一定第一个能获取锁。

常用方法摘要

//试图获取锁.   void lock() //如果当前线程未被中断,则获取锁.void lockInterruptibly() //仅在调用时锁未被另一个线程保持的情况下,才获取该锁.boolean tryLock() //如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁.  boolean tryLock(long timeout, TimeUnit unit) //试图释放此锁.    void unlock() //返回用来与此 Lock 实例一起使用的 Condition 实例.Condition newCondition() //如果此锁的公平设置为 true,则返回 true.boolean isFair() //返回正等待获取此锁的线程估计数.int getQueueLength()     //返回等待与此锁相关的给定条件的线程估计数.int getWaitQueueLength(Condition condition) //返回标识此锁及其锁定状态的字符串.String  toString()

Condition接口

//使当前线程在接收到信号前或被中断前一直保持等待状态.
void await()
          
//使当前线程在接收到信号前或被中断前或达到指定时间前一直保持等待状态(TimeUnit为时间单位).
boolean await(long time, TimeUnit unit)
          
//使当前线程在接收到信号前或被中断前或达到指定时间前一直保持等待状态(单位为毫秒).
long awaitNanos(long nanosTimeout)
 
//使当前线程在接收到信号前或被中断前或达到最后日期期限前一直保持等待状态.
boolean awaitUntil(Date deadline)
 
//唤醒一个在该Condition实例等待的线程.
void signal()
 
//唤醒所有在该Condition实例等待的线程.         
void signalAll()

一个Condition实例将与一个Lock实例进行绑定,作为该Lock实例的条件控制。

 Condition接口声明的方法调用前都需要先获取与此Condition相关的锁。

 await()、await(long time, TimeUnit unit)、awaitNanos(long nanosTimeout)、awaitUntil(Date deadline)这些方法调用后,则与此Condition相关的锁将以原子方式释放。

 signal()、signalAll()方法调用后,被唤醒的线程需要重新获取锁才能从await()方法进行返回。

使用示例:

/**
* @Auther: ZHUANGHAOTANG
* @Date: 2018/9/26 17:36
* @Description:
*/
public class TestReentranLock implements Runnable{

    /**
     * 可重入锁
     */
    private ReentrantLock reentrantLock = new ReentrantLock(true);

    /**
     * 锁条件
     */
    private Condition condition = reentrantLock.newCondition();

    /**
     * 业务处理
     */
    public void service(){
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+":尝试获取锁");
        reentrantLock.lock();
        System.out.println(threadName+":获取锁成功");
        try {
            System.out.println(threadName+":使当前线程等待,并释放锁资源。");
            condition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            reentrantLock.unlock();
            System.out.println(threadName+":释放锁");
        }
    }

    /**
     * 唤醒在该Condition实例等待的线程
     */
    public void signalAll(){
        reentrantLock.lock();
        condition.signalAll();
        reentrantLock.unlock();
    }

    @Override
    public void run() {
        service();
    }

    public static void main(String[] args) {

        TestReentranLock testReentranLock = new TestReentranLock();

        Thread threadA = new Thread(testReentranLock,"线程A");
        Thread threadB = new Thread(testReentranLock,"线程B");
        Thread threadC = new Thread(testReentranLock,"线程C");

        threadA.start();
        threadB.start();
        threadC.start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        testReentranLock.signalAll();

    }

}

公平锁执行结果:

线程B:尝试获取锁
线程A:尝试获取锁
线程B:获取锁成功
线程C:尝试获取锁
线程B:使当前线程等待,并释放锁资源。
线程A:获取锁成功
线程A:使当前线程等待,并释放锁资源。
线程C:获取锁成功
线程C:使当前线程等待,并释放锁资源。
线程B:释放锁
线程C:释放锁
线程A:释放锁

非公平锁执行结果:

线程B:尝试获取锁
线程A:尝试获取锁
线程A:获取锁成功
线程C:尝试获取锁
线程A:使当前线程等待,并释放锁资源。
线程C:获取锁成功
线程C:使当前线程等待,并释放锁资源。
线程B:获取锁成功
线程B:使当前线程等待,并释放锁资源。
线程A:释放锁
线程B:释放锁
线程C:释放锁

ReadWriteLock接口

//返回用于读取操作的锁.
Lock readLock()          
//返回用于写入操作的锁.
Lock writeLock()

ReentrantReadWriteLock类

构造方法

//创建一个ReentrantReadWriteLock实例.
ReentrantReadWriteLock()        
//创建一个具有给定公平策略的ReentrantReadWriteLock实例.
ReentrantReadWriteLock(boolean fair)

常用方法摘要

//返回用于读取操作的锁.
Lock ReentrantReadWriteLock。ReadLock。readLock()   
//返回用于写入操作的锁.
Lock ReentrantReadWriteLock。WriteLock。writeLock()
//返回等待获取读取或写入锁的线程估计数目.
int getQueueLength()
//如果此锁的公平设置为 true,则返回 true.
boolean isFair()
//返回标识此锁及其锁状态的字符串.
String toString()

ReadLock/WriteLock静态内部类

常用方法摘要

//试图获取锁.
void lock() 
//如果当前线程未被中断,则获取锁.
void lockInterruptibly()
          
//返回绑定到此 Lock 实例的新 Condition 实例.
Condition newCondition()
          
//仅在调用时锁为空闲状态才获取该锁.
boolean tryLock()
          
//如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁.
boolean tryLock(long time, TimeUnit unit)
          
//试图释放锁.
void unlock()
 
//返回标识此锁及其锁状态的字符串.
String toString()

因为ReadLock不支持条件,因此当调用了ReadLock的newCondition()方法时将会抛出UnsupportedOperationException异常。

使用ReentrantReadWriteLock的读锁以及写锁,将会遵循读读共享、写写互斥、读写互斥。

使用示例:

/**
* @Auther: ZHUANGHAOTANG
* @Date: 2018/9/26 18:04
* @Description:
*/
public class TestReentrantReadWriteLock implements Runnable{


    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(true);

    /**
     * 读锁
     */
    private Lock readLock = reentrantReadWriteLock.readLock();

    /**
     * 写锁
     */
    private Lock writeLock = reentrantReadWriteLock.writeLock();

    /**
     * 读取操作
     */
    public void reading(){
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+":尝试获取读锁");
        readLock.lock();
        System.out.println(threadName+":获取读锁成功");
        System.out.println(threadName+":释放读锁");
        readLock.unlock();
    }

    /**
     * 写入操作
     */
    public void writing(){
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName+":尝试获取写锁");
        writeLock.lock();
        System.out.println(threadName+":获取写锁成功");
        System.out.println(threadName+":释放写锁");
        writeLock.unlock();
    }


    public static void main(String[] args) {
        TestReentrantReadWriteLock testReentrantReadWriteLock = new TestReentrantReadWriteLock();

        Thread threadA = new Thread(testReentrantReadWriteLock,"线程A");
        Thread threadB = new Thread(testReentrantReadWriteLock,"线程B");
        Thread threadC = new Thread(testReentrantReadWriteLock,"线程C");

        threadA.start();
        threadB.start();
        threadC.start();
    }

}

读读共享执行结果:

@Overridepublic void run() {     
 //读读共享      
 reading();
}
线程A:尝试获取读锁
线程B:尝试获取读锁
线程A:获取读锁成功
线程A:释放读锁
线程C:尝试获取读锁
线程C:获取读锁成功
线程C:释放读锁
线程B:获取读锁成功
线程B:释放读锁

读锁能被多个线程同时获取,能提高读取的效率 (虽然只用读锁时可以不进行释放,但会影响写锁的获取)

写写互斥执行结果:

@Overridepublic void run() {  
    //写写互斥     
    writing();
}
线程A:尝试获取写锁
线程B:尝试获取写锁
线程A:获取写锁成功
线程C:尝试获取写锁
线程A:释放写锁
线程B:获取写锁成功
线程B:释放写锁
线程C:获取写锁成功
线程C:释放写锁

写锁同一时刻只能被一个线程获取。

读写互斥执行结果:

@Overridepublic void run() {      
   //读写互斥      
   writing();
  reading();
}
线程A:尝试获取写锁
线程C:尝试获取写锁
线程B:尝试获取写锁
线程A:获取写锁成功
线程A:释放写锁
线程A:尝试获取读锁
线程C:获取写锁成功
线程C:释放写锁
线程C:尝试获取读锁
线程B:获取写锁成功
线程B:释放写锁
线程B:尝试获取读锁
线程C:获取读锁成功
线程C:释放读锁
线程A:获取读锁成功
线程A:释放读锁
线程B:获取读锁成功
线程B:释放读锁

读的时候不能写,写的时候不能读,即获取读锁时如果写锁此时被线程持有则将等待写锁被释放,获取写锁时如果读锁此时有被线程持有则将等待读锁被释放且写锁未被持有。

3.Java中锁的分类

Java中的锁是按照锁的特性来进行划分的。

公平锁/非公平锁

公平锁:多线程按照申请锁的顺序获取锁。

非公平锁:多线程并非按照申请锁的顺序获取锁,即并未第一个lock()的线程能第一个获取锁。

对于ReentranLock以及ReentrantReadWriteLock锁其可以通过构造方法来设置是公平锁还是非公平锁。

对于Synchronized关键字其属于非公平锁。

共享锁/独享锁

共享锁:指该锁能被多个线程同时持有,对于ReadLock其属于共享锁。

独享锁:指该锁同一时刻只能被一个线程持有,对于ReentranLock、WriteLock、Synchronized其属于独享锁。

乐观锁/悲观锁

乐观锁和悲观锁并不是具体的锁特性,而是看待并发时的角度。

乐观锁:认为并发操作不会影响数据的完整性,因此无需进行加锁。

悲观锁:认为并发操作一定会影响数据的完整性,因此必须进行加锁。

读操作适用于乐观锁,即不进行加锁,能够提升读取数据的效率。

写操作适用于悲观锁,即一定要进行加锁。

分段锁

分段锁是指锁的设计,通过细化锁的粒度来控制并发的操作,在Java的ConcurrentHashMap中的segment就是通过分段锁的设计来实现并发操作。

偏向锁/轻量级锁/重量级锁

偏向锁、轻量级锁、重量级锁都是指锁的不同状态而且是针对Synchronized关键字而言的。

偏向锁:指同步方法或同步语句块一直只被一个线程所持有,则此时锁的状态为偏向锁,会降低该线程获取锁的成本。

轻量级锁:当锁的状态为偏向锁,若被其他线程访问,则此时其他线程将通过自旋的方式尝试获取锁,则此时锁的状态为轻量级锁。

自旋即通过循环一定次数的方式尝试获取锁,使用此方式不会阻塞线程,缺点是消耗CPU的性能。

重量级锁:当锁的状态是轻量级锁,若其他线程自旋过后仍未获取到锁,则此时锁的状态为重量级锁,此时其他线程将会进入阻塞状态,性能降低。

当锁的状态为偏向锁时性能最高,重量级锁时性能最低。

以上是Java中的锁是什么?Java中锁的详细介绍的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
是否有任何威胁或增强Java平台独立性的新兴技术?是否有任何威胁或增强Java平台独立性的新兴技术?Apr 24, 2025 am 12:11 AM

新兴技术对Java的平台独立性既有威胁也有增强。1)云计算和容器化技术如Docker增强了Java的平台独立性,但需要优化以适应不同云环境。2)WebAssembly通过GraalVM编译Java代码,扩展了其平台独立性,但需与其他语言竞争性能。

JVM的实现是什么,它们都提供了相同的平台独立性?JVM的实现是什么,它们都提供了相同的平台独立性?Apr 24, 2025 am 12:10 AM

不同JVM实现都能提供平台独立性,但表现略有不同。1.OracleHotSpot和OpenJDKJVM在平台独立性上表现相似,但OpenJDK可能需额外配置。2.IBMJ9JVM在特定操作系统上表现优化。3.GraalVM支持多语言,需额外配置。4.AzulZingJVM需特定平台调整。

平台独立性如何降低发展成本和时间?平台独立性如何降低发展成本和时间?Apr 24, 2025 am 12:08 AM

平台独立性通过在多种操作系统上运行同一套代码,降低开发成本和缩短开发时间。具体表现为:1.减少开发时间,只需维护一套代码;2.降低维护成本,统一测试流程;3.快速迭代和团队协作,简化部署过程。

Java的平台独立性如何促进代码重用?Java的平台独立性如何促进代码重用?Apr 24, 2025 am 12:05 AM

Java'splatformindependencefacilitatescodereusebyallowingbytecodetorunonanyplatformwithaJVM.1)Developerscanwritecodeonceforconsistentbehavioracrossplatforms.2)Maintenanceisreducedascodedoesn'tneedrewriting.3)Librariesandframeworkscanbesharedacrossproj

您如何在Java应用程序中对平台特定问题进行故障排除?您如何在Java应用程序中对平台特定问题进行故障排除?Apr 24, 2025 am 12:04 AM

要解决Java应用程序中的平台特定问题,可以采取以下步骤:1.使用Java的System类查看系统属性以了解运行环境。2.利用File类或java.nio.file包处理文件路径。3.根据操作系统条件加载本地库。4.使用VisualVM或JProfiler优化跨平台性能。5.通过Docker容器化确保测试环境与生产环境一致。6.利用GitHubActions在多个平台上进行自动化测试。这些方法有助于有效地解决Java应用程序中的平台特定问题。

JVM中的类加载程序子系统如何促进平台独立性?JVM中的类加载程序子系统如何促进平台独立性?Apr 23, 2025 am 12:14 AM

类加载器通过统一的类文件格式、动态加载、双亲委派模型和平台无关的字节码,确保Java程序在不同平台上的一致性和兼容性,实现平台独立性。

Java编译器会产生特定于平台的代码吗?解释。Java编译器会产生特定于平台的代码吗?解释。Apr 23, 2025 am 12:09 AM

Java编译器生成的代码是平台无关的,但最终执行的代码是平台特定的。1.Java源代码编译成平台无关的字节码。2.JVM将字节码转换为特定平台的机器码,确保跨平台运行但性能可能不同。

JVM如何处理不同操作系统的多线程?JVM如何处理不同操作系统的多线程?Apr 23, 2025 am 12:07 AM

多线程在现代编程中重要,因为它能提高程序的响应性和资源利用率,并处理复杂的并发任务。JVM通过线程映射、调度机制和同步锁机制,在不同操作系统上确保多线程的一致性和高效性。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),