精华内容
下载资源
问答
  • 同步锁分类对象(this)类(类的字节码文件对象即类名.class)字符串(比较特别)应用场景在多线程下对共享资源的安全操作。需求:启动5个线程对共享资源total进行安全操作。同步锁在多线程单例模式下的使用以上三类...

    同步锁分类

    对象锁(this)

    类锁(类的字节码文件对象即类名.class)

    字符串锁(比较特别)

    应用场景

    在多线程下对共享资源的安全操作。

    需求:启动5个线程对共享资源total进行安全操作。

    同步锁在多线程单例模式下的使用

    以上三类同步锁都可以。

    package cn.myThread;

    public class MyThread implements Runnable {

    private static int total = 10;

    @Override

    public void run() {

    synchronized (this){ //使用this对象锁

    //synchronized (MyThread.class){ //使用MyThread.class类锁

    //synchronized (""){//使用字符串锁

    System.out.println(Thread.currentThread().getName() + "正在运行");

    try {

    Thread.sleep(100);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    total--;

    System.out.println(total);

    System.out.println(Thread.currentThread().getName() + "线程结束");

    }

    }

    }

    package cn.test;

    import cn.myThread.MyThread;

    public class TestMyThread {

    public static void main(String[] args){

    MyThread myThread = new MyThread();

    Thread thread = null;

    for (int i = 1 ; i <= 5 ; i++){

    thread = new Thread(myThread,"线程"+i); //开启5个线程,传入同一个对象

    thread.start();

    }

    }

    }

    线程1正在运行

    9

    线程1线程结束

    线程3正在运行

    8

    线程3线程结束

    线程5正在运行

    7

    线程5线程结束

    线程2正在运行

    6

    线程2线程结束

    线程4正在运行

    5

    线程4线程结束

    分析:从运行结果可以看出5个线程串行执行同步锁里面的代码,因为5个线程中的同步锁对象this指向同一个的对象(同步锁对象MyThread.class类锁是同一个对象、同步锁对象 ”” 字符串锁是同一个对象),所以5个线程会串行执行同步锁里面的代码。

    同步锁在多线程多例模式下的使用

    错误用法

    package cn.myThread;

    public class MyThread implements Runnable {

    private static int total = 10;

    @Override

    public void run() {

    synchronized (this){//使用this对象锁

    System.out.println(Thread.currentThread().getName() + "正在运行");

    try {

    Thread.sleep(100);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    total--;

    System.out.println(total);

    System.out.println(Thread.currentThread().getName() + "线程结束");

    }

    }

    }

    package cn.test;

    import cn.myThread.MyThread;

    public class TestMyThread {

    public static void main(String[] args){

    Thread thread = null;

    for (int i = 1 ; i <= 5 ; i++){

    thread = new Thread(new MyThread(),"线程"+i);//开启5个线程,传入5个不同对象

    thread.start();

    }

    }

    }

    线程2正在运行

    线程1正在运行

    线程3正在运行

    线程5正在运行

    线程4正在运行

    9

    7

    9

    8

    线程1线程结束

    线程5线程结束

    线程2线程结束

    线程3线程结束

    6

    线程4线程结束

    分析:从运行结果可以看出5个线程并行执行同步锁里面的代码,因为5个线程中的同步锁对象this指向5个不同的对象,所以5个线程会同时执行同步锁里面的代码。

    正确用法

    方式一:

    package cn.myThread;

    public class MyThread implements Runnable {

    private static int total = 10;

    @Override

    public void run() {

    synchronized (MyThread.class){//使用MyThread.class类锁

    System.out.println(Thread.currentThread().getName() + "正在运行");

    try {

    Thread.sleep(100);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    total--;

    System.out.println(total);

    System.out.println(Thread.currentThread().getName() + "线程结束");

    }

    }

    }

    package cn.test;

    import cn.myThread.MyThread;

    public class TestMyThread {

    public static void main(String[] args){

    Thread thread = null;

    for (int i = 1 ; i <= 5 ; i++){

    thread = new Thread(new MyThread(),"线程"+i); //开启5个线程,传入5个不同对象

    thread.start();

    }

    }

    }

    线程1正在运行

    9

    线程1线程结束

    线程5正在运行

    8

    线程5线程结束

    线程4正在运行

    7

    线程4线程结束

    线程3正在运行

    6

    线程3线程结束

    线程2正在运行

    5

    线程2线程结束

    分析:从运行结果可以看出5个线程串行执行同步锁里面的代码,因为5个线程中的同步锁对象MyThread.class类锁是同一个对象,所以5个线程会串行执行同步锁里面的代码。

    方式二:

    package cn.myThread;

    public class MyThread implements Runnable {

    private static int total = 10;

    @Override

    public void run() {

    synchronized (""){//使用字符串锁

    System.out.println(Thread.currentThread().getName() + "正在运行");

    try {

    Thread.sleep(100);

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    total--;

    System.out.println(total);

    System.out.println(Thread.currentThread().getName() + "线程结束");

    }

    }

    }

    package cn.test;

    import cn.myThread.MyThread;

    public class TestMyThread {

    public static void main(String[] args){

    Thread thread = null;

    for (int i = 1 ; i <= 5 ; i++){

    thread = new Thread(new MyThread(),"线程"+i); //开启5个线程,传入5个不同对象

    thread.start();

    }

    }

    }

    线程1正在运行

    9

    线程1线程结束

    线程4正在运行

    8

    线程4线程结束

    线程5正在运行

    7

    线程5线程结束

    线程3正在运行

    6

    线程3线程结束

    线程2正在运行

    5

    线程2线程结束

    分析:从运行结果可以看出5个线程串行执行同步锁里面的代码,因为5个线程中的同步锁对象 ”” 字符串锁是同一个对象,所以5个线程会串行执行同步锁里面的代码。

    以上这篇java同步锁的正确使用方法(必看篇)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

    展开全文
  • Java 多线程开发中,如果涉及到共享资源操作场景,那就必不可少要和 Java 打交道。Java 中的机制主要分为 Lock 和 Synchronized ,本文主要分析 Java 机制的使用和实现原理,按照 Java 使用、JDK 中实现、...

    Java 多线程开发中,如果涉及到共享资源操作场景,那就必不可少要和 Java 锁打交道。

    Java 中的锁机制主要分为 Lock 和 Synchronized ,本文主要分析 Java 锁机制的使用和实现原理,按照 Java 锁使用、JDK 中锁实现、系统层锁实现的顺序来进行分析,话不多说,let’s go~

    一、Java 锁使用

    在 Lock 接口出现之前,Java 程序是靠 synchronized 关键字实现锁功能的,而 JavaSE 5 之后,并发包中新增了 Lock 接口(以及相关实现类)用来实现锁功能,它提供了与 synchronized 关键字类似的同步功能,只是在使用时需要显式地获取和释放锁。虽然它缺少了(通过 synchronized 块或者方法)隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种 synchronized 关键字所不具备的同步特性。

    Java 锁使用示例:

    Lock lock = new ReentrantLock();lock.lock();try {    // ..} finally {    lock.unlock();}

    注意:在 finally 块中释放锁,目的是保证在获取到锁之后,最终能够被释放。不要将获取锁的过程写在 try 块中,因为如果在获取锁(自定义锁的实现)时发生了异常,异常抛出的同时,会提前进行 unlock 导致 IllegalMonitorStateException 异常。

    Lock 相较于 Synchronized 优势如下:

    • 可中断获取锁 :使用 synchronized 关键字获取锁的时候,如果线程没有获取到被阻塞了,那么这个时候该线程是不响应中断 (interrupt) 的,而使用 Lock.lockInterruptibly() 获取锁时被中断,线程将抛出中断异常。
    • 可非阻塞获取锁 :使用 synchronized 关键字获取锁时,如果没有成功获取,只有被阻塞,而使用 Lock.tryLock() 获取锁时,如果没有获取成功也不会阻塞而是直接返回 false。
    • 可限定获取锁的超时时间 :使用 Lock.tryLock(long time, TimeUnit unit)。
    • 同一个所对象上可以有多个等待队列(Conditin,类似于 Object.wait(),支持公平锁模式)。

    Lock 除了更多的功能之外,有一个很大的优势:synchronized 的同步是 jvm 底层实现的,对一般程序员来说程序遇到出乎意料的行为的时候,除了查官方文档几乎没有别的办法;而显示锁除了个别操作用了底层的 Unsafe 类 (LockSupport 封装了 Unsafe 类) 之外,几乎都是用 java 语言实现的,我们可以通过学习显示锁的源码,来更加得心应手的使用显示锁。

    当然,Lock 也不是完美的,否则 java 就不会保留着 synchronized 关键字了,显示锁的缺点主要有两个:

    • 使用比较复杂,这点之前提到了,需要手动加锁,解锁,而且还必须保证在异常状态下也要能够解锁。而 synchronized 的使用就简单多了。
    • 效率较低,synchronized 关键字毕竟是 jvm 底层实现的,因此用了很多优化措施来优化速度 (偏向锁、轻量锁等),而显示锁的效率相对低一些。

    1.1 Synchronized

    Synchronized 在 JVM 里的实现是基于进入和退出 Monitor 对象来实现方法同步和代码块同步的。monitorenter 指令是在编译后插入到同步代码块的开始位置,而 monitorexit 是插入到方法结束处和异常处,JVM 要保证每个 monitorenter 必须有对应的 monitorexit 与之配对。任何对象都有一个 monitor 与之关联,当且一个 monitor 被持有后,它将处于锁定状态。线程执行到 monitorenter 指令时,将会尝试获取对象所对应的 monitor 的所有权,即尝试获得对象的锁。

    synchronized 用的锁是存在 Java 对象头里的。如果对象是数组类型,则虚拟机用 3 个字宽(Word)存储对象头,如果对象是非数组类型,则用 2 字宽存储对象头。

    b687652f7be4101b7abd79d0ec87dfb4.png

    关于对 Java 象头,可以使用 JOL 工具(jol-core)类直接打印对象头,如下所示:

    d11e143c87810b909951d2c404cc765d.png

    1.2 锁升级

    Java 1.6 为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”,在 Java SE 1.6 中,锁一共有 4 种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。

    锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率。

    5092164e3605d1f19ee371df6c14567a.png

    二、JDK 中锁实现

    JDK 中 Lock 是一个接口,其定义了锁获取和释放的基本操作:

    fe4ed53dde82604085a113ba5a2dd48d.png

    Lock 底层是基于 AQS 同步器(AbstractQueuedSynchronizer)的,AQS 是用来构建锁或者其他同步组件的基础框架,它使用了一个 int 成员变量表示同步状态,通过内置的 FIFO 队列来完成资源获取线程的排队工作,并发包的作者(Doug Lea)期望它能够成为实现大部分同步需求的基础,事实上目前的 JDK 并发包都是基于 AQS 来完成同步需求的。

    关于锁和 AQS,可以这样理解二者之间的关系:锁是面向使用者的,它定义了使用者与锁交互的接口(比如可以允许两个线程并行访问),隐藏了实现细节;同步器面向的是锁的实现者,它简化了锁的实现方式,屏蔽了同步状态管理、线程的排队、等待与唤醒等底层操作。锁和同步器很好地隔离了使用者和实现者所需关注的领域。

    这里稍微分析下 AQS,其是由一个同步状态 +FIFO 的同步队列组成,提供了同步队列、独占式同步状态获取与释放、共享式同步状态获取与释放以及超时获取同步状态等同步器的核心数据结构与模板方法。简单来说就是,当线程需要阻塞时就将其放到同步队列中,等到该唤醒时就将其移出队列并唤醒,使其继续工作。关于 AQS 具体的实现原理,可以参考阿里大神写的《Java 并发编程的艺术》。

    AQS 当需要阻塞或唤醒一个线程的时候,都会使用 LockSupport 工具类来完成相应工作。LockSupport 定义了一组的公共静态方法,这些方法提供了最基本的线程阻塞和唤醒功能,而 LockSupport 也成为构建同步组件的基础工具。LockSupport 定义了一组以 park 开头的方法用来阻塞当前线程,以及 unpark(Thread thread) 方法来唤醒一个被阻塞的线程。

    LockSupport 提供的阻塞和唤醒方法:

    2bd29311a81d37fd59bdf8e393206241.png

    LockSupport 常用方法源码如下:

    // LockSupportpublic static void park(Object blocker) {    Thread t = Thread.currentThread();    // blocker 在什么对象上进行的阻塞操作    setBlocker(t, blocker);    UNSAFE.park(false, 0L);    setBlocker(t, null);} public static void parkNanos(Object blocker, long nanos) {    if (nanos > 0) {        Thread t = Thread.currentThread();        setBlocker(t, blocker);        // 超时阻塞        UNSAFE.park(false, nanos);        setBlocker(t, null);    }} public static void unpark(Thread thread) {    if (thread != null)        UNSAFE.unpark(thread);}

    三、系统层锁实现

    UNSAFE 使用 park 和 unpark 进行线程的阻塞和唤醒操作,park 和 unpark 底层是借助系统层(Linux 下)方法 pthread_mutex 和 pthread_cond 来实现的,通过 pthread_cond_wait函数可以对一个线程进行阻塞操作,在这之前,必须先获取 pthread_mutex ,通过 pthread_cond_signal 函数对一个线程进行唤醒操作。

    pthread_mutex 和 pthread_cond 使用示例如下:

    void *r1(void *arg){    pthread_mutex_t* mutex = (pthread_mutex_t *)arg;    static int cnt = 10;     while(cnt--)    {        printf("r1: I am wait.");        pthread_mutex_lock(mutex);        pthread_cond_wait(&cond, mutex); /* mutex 参数用来保护条件变量的互斥锁,调用 pthread_cond_wait 前 mutex 必须加锁 */        pthread_mutex_unlock(mutex);    }    return "r1 over";} void *r2(void *arg){    pthread_mutex_t* mutex = (pthread_mutex_t *)arg;    static int cnt = 10;     while(cnt--)    {        pthread_mutex_lock(mutex);        printf("r2: I am send the cond signal.");        pthread_cond_signal(&cond);        pthread_mutex_unlock(mutex);        sleep(1);    }    return "r2 over";}

    注意,Linux 下使用 pthread_cond_signal 的时候,会产生“惊群”问题的,但是 Java 中是不会存在这个“惊群”问题的,那么 Java 是如何处理的呢?

    实际上,Java 只会对一个线程调用 pthread_cond_signal 操作,这样肯定只会唤醒一个线程,也就不存在所谓的惊群问题。Java 在语言层面实现了自己的线程管理机制(阻塞、唤醒、排队等),每个 Thread 实例都有一个独立的 pthread_mutex 和 pthread_cond (系统层面的 /C 语言层面),在 Java 语言层面上对单个线程进行独立唤醒操作。(怎么感觉 Java 中线程有点小可怜呢,只能在 Java 线程库的指挥下作战,竟然无法直接获取同一个 pthread_mutex 或者 pthread_cond 。但是 Java 这种实现线程机制的实现实在太巧妙了,虽然底层都是使用 pthread_mutex 和 pthread_cond 这些方法,但是貌似 C/C++ 还没这么强大易用的线程库)

    具体 LockSuuport.park 和 LockSuuport.unpark 的底层实现可以参考对应 JDK 源码,下面看一下 gdb 打印处于 LockSuuport.park 时的线程状态信息:

    499a3112ed7eba99014a6c08fae0a2c1.png

    由上图可知底层确实是基于 pthread_cond 函数来实现的。

    小结

    了解 Java 锁机制之后,在后续的业务开发过程中,当需要进行同步时,优先考虑使用 synchronized 关键字,只有 synchronized 关键字不能满足需求时,才考虑使用显示锁(Lock)。

    展开全文
  • Java锁

    2021-01-27 14:43:32
    乐观锁和悲观锁是一种策略,是否需要锁住同步资源。 乐观锁 乐观锁的概念:乐观锁认为自己在使用资源时,不会有其他线程来修改该资源,所以不需要对资源进行加锁,只需要在更新数据时去判断有没有其他线程修改了...

    Java中提供了各种各样的锁,本文通过对锁进行分类,介绍锁的基本概念

    乐观锁和悲观锁

    乐观锁和悲观锁是一种策略,是否需要锁住同步资源。

    乐观锁

    • 乐观锁的概念:乐观锁认为自己在使用资源时,不会有其他线程来修改该资源,所以不需要对资源进行加锁,只需要在更新数据时去判断有没有其他线程修改了数据。
    • 乐观锁在Java中是通过使用无锁编程来实现,最常采用的是CAS算法。
    • 乐观锁适合读操作多的场景,不加锁可以使读操作的性能提升

    悲观锁

    • 悲观锁的概念:悲观锁认为自己在使用数据的时候一定有别的线程来修改数据因此在获取数据的时候会先加锁,确保数据不会被别的线程修改。
    • 其他线程需要使用该同步资源时,必须进行等待,直到持锁线程释放锁后,尝试去获取锁。
    • 悲观锁适合写操作多的场景,先加锁可以保证写操作时数据正确。

    自旋锁和适应性自旋锁

    • 使用场景:

      ​ 阻塞或唤醒一个线程需要CPU切换状态来完成,需要消耗处理器时间,如果同步代码块内容过于简单,转换的时间比执行代码的时间还长。

      ​ 此时我们可以让请求锁的线程不放弃CPU时间(稍等一下),看看持有锁的线程是否很快就释放锁。即让请求线程进行自旋,自旋结束前锁定资源线程已释放锁,则可以直接获取同步资源(锁),线程不需要阻塞,避免线程切换带来的开销

    • 自旋等待虽然避免了线程切换的开销,但它要占用处理器时间。如果锁被占用的时间很短,自旋等待的效果就会非常好。自旋应有限定次数(等待多久),没有成功获得则挂起线程

    • JDK6引入自适应自旋锁,即自旋时间不固定,而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。

    四种锁状态

    Java对象头

    同步时获取对象的锁,对象锁就类似一个标志,这个标志存放在Java对象的对象头

    • Java SE 1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态

    • 锁可以升级但不能降级,意味着偏向锁升级成轻量级锁后不能降级成偏向锁

    无锁

    CAS原理及应用即是无锁的实现

    • 无锁没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功。
    • 无锁的特点就是修改操作在循环内进行,线程会不断的尝试修改共享资源。如果没有冲突就修改成功并退出,否则就会继续循环尝试。

    偏向锁

    大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。

    • 偏向锁获取

      ​ 当一个线程访问同步块并获取锁时,会在对象头栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁,只需简单地测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。

      ​ 如果测试成功,表示线程已经获得了锁。如果测试失败,则需要再测试一下Mark Word中偏向锁的标识是否设置成1(表示当前是偏向锁):如果没有设置,则使用CAS竞争锁;如果设置了,则尝试使用CAS将对象头的偏向锁指向当前线程

    • 偏向锁的撤销

      ​ 偏向锁使用了一种等到竞争出现才释放锁的机制,所以当其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁。

      ​ 偏向锁的撤销,对象可能处于两种状态:不可偏向的无锁状态不可偏向已锁状态(轻量级锁)。触发撤销操作时,原线程可能执行完了同步代码块,对象闲置;如果原线程没有执行完毕,偏向锁依旧有效,升级为轻量级加锁的状态。

    轻量级锁

    轻量级锁是指当前锁是偏向锁的时候,被另外的线程所访问,那么偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,从而提高性能。

    • 加锁

      ​ 线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中,官方称为Displaced Mark Word。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁

    • 解锁

      ​ 轻量级解锁时,会使用原子的CAS操作将Displaced Mark Word替换回到对象头,如果成功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁。即当自旋超过一定的次数,或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁升级为重量级锁。

    重量级锁

    ​ 升级为重量级锁时,锁标志的状态值变为“10”,此时Mark Word中存储的是指向重量级锁的指针,此时等待锁的线程都会进入阻塞状态。

    公平锁和非公平锁

    公平锁

    多个线程进入队列种排队,第一个线程才能获取锁

    • 特点:
      • 公平,等待锁的线程都有机会获得锁
      • 等待队列的其他线程都会阻塞,CPU唤醒阻塞线程的开销大

    非公平锁

    线程会直接尝试获取锁,获取不到则进入队尾等待

    • 非公平锁有可能出现后申请先获得锁的情况
    • 可以减少唤起线程的开销,整体的吞吐效率高
    • 队列中的锁可能获取不到锁或是很久才获取到锁

    可重入锁和非可重入锁

    可重入锁

    ​ 同一个线程在外层方法获取锁的时候,再进入该线程的内层方法会自动获取锁(前提锁对象得是同一个对象或者class),不会因为之前已经获取过还没释放而阻塞

    非可重入锁

    ​ 同一个线程在外层方法获取锁的时候,再进入该线程的内层方法,需要外层释放锁后重新获取,可能或出现死锁状态。

    独享锁和共享锁

    独享锁

    ​ 独享锁,又称为排他锁,指该锁一次只能被一个线程所持有。如果线程T对数据A加上排它锁后,则其他线程不能再对A加任何类型的锁。获得排它锁的线程即能读数据又能修改数据。

    共享锁

    ​ 共享锁是指该锁可被多个线程所持有。如果线程T对数据A加上共享锁后,则其他线程只能对A再加共享锁,不能加排它锁。获得共享锁的线程只能读数据,不能修改数据。

    展开全文
  • 乐观锁又叫非互斥同步锁...持悲观态度,认为每次执行这个同步资源的时候都会有线程争抢这个资源,如果不锁住就会发生错误。所以每次执行时都会锁住,让其他人等待执行完成释放锁后在拿到锁再执行。如synchronized和Loc

    乐观锁又叫非互斥同步锁,悲观锁又叫互斥同步锁。

    悲观锁的劣势

    • 阻塞和唤醒带来的性能开销。
    • 永久阻塞问题。如果持有锁的线程发生无限循环或者死锁等活跃性的问题,那么等待获取锁执行的线程将无法执行。
    • 优先级反转问题。如果我们设置了优先级,当优先级高的线程需要等待优先级低的线程锁的时候,会让线程的优先级反转。

    悲观锁概念

    持悲观态度,认为每次执行这个同步资源的时候都会有线程争抢这个资源,如果不锁住就会发生错误。所以每次执行时都会锁住,让其他人等待执行完成释放锁后在拿到锁再执行。如synchronizedLock接口相关类

    乐观锁概念

    持乐观态度,认为每次执行这个同步资源的时候都没有线程争抢这个资源。所以执行时不会锁住资源,在更新时会对比我修改期间数据有没有被别人修改过,如果数据与开始一致,证明只有我们自己在操作,就正常修改数据;如果数据与开始不一致,证明有人修改过,那么就不会修改数据,执行放弃、报错、重试等相关策略。如CAS算法实现的相关操作,原子类、并发容器等。git中push操作也是乐观锁,push时如果有人版本号领先我们,则提交失败。

    开销对比

    • 悲观锁的开销主要是线程阻塞唤醒带来的性能开销。
    • 乐观锁的开销主要是线程自旋所带来的cpu性能开销。

    使用场景

    悲观锁适用于并发写入多的情况,适用于持有锁时间比较长的情况,悲观锁可以避免线程自旋的性能开销。

    • IO操作
    • 代码量大,逻辑比较多,相对来说比较耗时
    • 并发大,线程竞争激烈。

    乐观锁适用于并发写入少,大部分是读取数据的场景。

    相关文章

    Java中锁的分类及概念

    展开全文
  • java锁机制

    2021-01-15 16:16:39
    悲观锁:线程会锁住同步资源 乐观锁:线程不会锁住同步资源 悲观锁适合写操作多的场景,先加锁可以保证写操作时数据正确。 乐观锁适合读操作多的场景,不加锁的特点能够使其读操作的性能大幅提升。 问题1:...
  • 线程是否要锁住同步资源锁住悲观锁不锁住乐观锁锁住同步资源失败 线程是否要阻塞阻塞不阻塞自旋锁,适应性自旋锁多个线程竞争同步资源的流程细节有没有区别不锁住资源,多个线程只有一个能修改资源成功,其它线程会...
  • 理解Java锁机制

    2020-03-13 15:48:38
    理解Java锁机制 ... 乐观锁-悲观锁(主线程锁不锁住同步资源)CAS机制问题悲观锁4. 自旋锁和适应性自旋锁(均不阻塞线程,是否有自旋次数限制)5. 公平锁-非公平锁(是否允许插队)6. 可重入锁-非可重入锁(是...
  • 并发-JAVA锁 分类

    2019-12-27 19:48:48
    1.线程要不要锁住同步资源? 锁住--悲观锁 不锁住--乐观锁 2.锁住同步资源如果失败,线程要不要阻塞? 阻塞 不阻塞--自旋锁,适应性自旋锁 3.多个线程竞争同步资源的流程细节上的区别? 不锁住资源,多...
  • 线程是否要锁住同步资源锁住悲观锁不锁住乐观锁锁住同步资源失败 线程是否要阻塞阻塞不阻塞自旋锁,适应性自旋锁多个线程竞争同步资源的流程细节有没有区别不锁住资源,多个线程只有一个能修改资源成功,其它线程会...
  • java 同步块(Java Synchronized Blocks)Java 同步块包括方法同步和代码块同步java 同步可以避免资源竞争,避免死锁。...一个对象上的所有同步块只能被一个线程锁住。其他所有的线程试图访问同步块的方法,...
  • ---Java主流

    2021-01-18 01:13:05
    1. 线程要不要锁住同步资源? 锁住-----悲观锁 不锁住-----乐观锁 2. 锁住同步资源失败,线程要不要阻塞? 阻塞-----悲观锁 不阻塞 。自旋锁 。适应性自旋锁 3. 多个线程竞争同步资源的流程细节有没有区别
  • java的分类

    2019-09-02 21:16:44
    1.线程是否要锁住同步资源: 锁住:悲观锁 不锁住: 乐观锁 CAS 2.锁住同步资源失败,线程是否要阻塞: 阻塞 不阻塞: 自旋锁 适应性自旋锁 3.多个线程竞争同步资源的流程细节有没有区别: 不锁住资源,多...
  • 线程同步需要关键字synchronized来锁资源。 有两种线程同步的方式 1.同步化方法 ...在对象被锁住的同时,其他线程不能进入该方法,也不能进入该对象定义的其他同步化方法,但是该对象的非同步化方法可以被...
  • 线程是否要锁住同步资源锁住 悲观锁不锁住 乐观锁锁住同步资源失败 线程是否要阻塞阻塞不阻塞自旋锁,适应性自旋锁多个线程竞争同步资源的流程细节有没有区别不锁住资源,多个线程只有一个能修改资源成功,其它线程...
  • 线程如果锁住了某个资源,致使其他线程无法访问的这种锁被称为悲观锁,相反,线程不锁住资源的锁被称为乐观锁,而自旋锁是基于 CAS 机制实现的,CAS又是乐观锁的一种实现,那么对于锁来说,多个线程同步访问某个资源...
  • Java悲观与乐观

    千次阅读 2020-02-09 16:30:53
    Java悲观锁与乐观锁锁的目的实例悲观锁实现乐观锁实现总结 锁的目的 多线程编程如有共用资源的使用时,需要保证数据安全,资源需要...悲观锁是主要使用synchronized实现,通过锁住对应的对象,独占资源的方式。 de...
  • Java (一)

    2021-03-27 12:35:42
    作用于静态方法时,锁住Class实例,相当于类的全局锁,所有调用该方法的线程都会被锁。 作用于一个对象实例时,锁住的是所有以该对象为锁的代码块。 核心组件 wait Set: Contention List Entry
  • 线程是否要锁住同步资源锁住 悲观锁不锁住 乐观锁锁住同步资源失败 线程是否要阻塞阻塞不阻塞自旋锁,适应性自旋锁多个线程竞争同步资源的流程细节有没有区别不锁住资源,多个线程只有一个能修改资源成功,其它线程...
  • java锁的种类与介绍

    2021-02-01 10:44:05
    顾名思义,锁就是将一种资源锁住,防止其他线程同步修改。锁机制是保证获取数据有序性的重要手段,为此java提供了大量的锁。无论是在面试或学习中,会遇到各种锁,如对象锁与类锁、轻量级与重量级锁、悲观锁与乐观锁...
  • 线程是否要锁住同步资源锁住悲观锁不锁住乐观锁锁住同步资源失败 线程是否要阻塞阻塞不阻塞自旋锁,适应性自旋锁多个线程竞争同步资源的流程细节有没有区别不锁住资源,多个线程只有一个能修改资源成功,其它线程会...
  • Java 同步块包括方法同步和代码块同步java 同步可以避免资源竞争...一个对象上的所有同步块只能被一个线程锁住。其他所有的线程试图访问同步块的方法,都要等到占用资源的线程释放了才能访问。synchronized关键字...
  • java中的分类

    2021-03-15 21:59:41
    锁的分类要不要锁住同步资源-乐观锁和悲观锁自旋锁和适应性自旋锁公平锁和非公平锁可重入锁 非可重入锁 java中的锁有很多种类,常见的有公平锁和非公平锁、乐观锁和悲观锁、可重入和不可重入锁等。 下面做了一个分类...
  • 线程是否要锁住同步资源锁住 悲观锁不锁住 乐观锁锁住同步资源失败 线程是否要阻塞阻塞不阻塞自旋锁,适应性自旋锁多个线程竞争同步资源的流程细节有没有区别不锁住资源,多个线程只有一个能修改资源成功,其它线程...
  • java的种类及用法

    2020-06-02 16:29:47
    线程是否需要锁住同步资源 实现方法:synchronized 悲观锁 乐观锁:AtomicInteger,通常实现要用到CAS算法比较并替换 (***CAS 即比较并替换,实现并发算法时常用到的一种技术。CAS操作包含三个操作数——内存位置...
  • 这个就相当于Qt5里面的 QMutex互斥量,在一个线程 使用一个公共资源之前 调用 mutex.lock(),锁住后只允许当前线程调用此资源 其余线程等待,然后 调用 mutex.unlock()解锁,解锁后大家都可以抢,然后又有一个锁定。...
  • Java多线程的同步代码块synchronized(对象){需要同步的代码}同步代码块可以解决安全问题的根本原因在于那个对象快上,这个对象如同的功能。多个线程需要同一个,才能,所以这个对象需要在run()方法外面...
  • Java-分析

    2020-04-05 16:59:09
    前言 Java锁是Java中一个非常重要的一个知识,是作为一个中高级...如果操作一个数据(资源)不是一个原子操作的话,那么在多线程情况下就有可能出现数据异常的问题,所以锁住主要的作用是处理多线程情况下的数据同...
  • 在上一篇中,我们讲到了多线程是如何处理共享资源的,以及保证他们...但是很多人看到这个东西会感到困惑:“都说同步机制是通过对象锁来实现的,但是这么一个关键字,我也看不出来Java程序锁住了哪个对象 阿?“ ...
  • 线程是否要锁住同步资源锁住 悲观锁不锁住 乐观锁锁住同步资源失败 线程是否要阻塞阻塞不阻塞自旋锁,适应性自旋锁多个线程竞争同步资源的流程细节有没有区别不锁住资源,多个线程只有一个能修改资源成功,其它线程...
  • synchronized同步锁,锁住的是对象,该对象被锁住之后,只能有一个线程可以使用该对象,其他线程如果要使用该对象,只能等上一个线程使用完了过后才行 同步分为同步代码块和同步方法 1. 同步代码块 synchronized...

空空如也

空空如也

1 2 3 4 5 6
收藏数 112
精华内容 44
关键字:

java锁住同步资源

java 订阅