美文网首页一些收藏
Java--多线程锁机制

Java--多线程锁机制

作者: aruba | 来源:发表于2021-10-13 22:29 被阅读0次
上次通过三个例子,了解了Java并发三个特性,也分析了volatile不能解决原子性问题的原因,要解决原子性问题,就需要用到锁

一、轻量级锁与重量级锁

1.锁的概念

锁:一个线程对共享对象进行加锁,别的线程访问该对象时会处于等待状态,直到锁被释放,才能继续执行
补充:volatile底层也是通过lock原子性操作,但它只对写入共享变量值时进行了加锁,别的线程可能已经使用旧值副本在进行计算了、或者已经在写入了等情况,导致不同步问题

2.轻量级锁(自旋锁)

由于我们希望cpu尽可能多的时间使用在执行代码上,而内核线程切换会消耗较多时间,所以出现了对于短时间的等待操作进行优化
自旋锁,在等待时,不会切换到内核态去切换线程,还是在当前线程继续执行,只不过执行的是一个循环,所以称之为自旋,这样做争对短时间的等待,性能会更高,造成的时间浪费也短。
缺点:对于长时间的等待,它一直占用着cpu资源,别的线程得不到执行

3.重量级锁

重量级锁就是切换到内核态,由OS线程调度切换到其他线程执行,当前线程进入等待队列,后面重新竞争获取锁

二、悲观锁与乐观锁

悲观锁与乐观锁是两种概念,是对线程同步的两种不同实现方式

1. 悲观锁

线程对一个共享变量进行访问,它就自动加锁,所以只能有一个线程访问它
悲观锁适合写操作多的场景,先加锁可以保证写操作时数据正确。
缺点:只有一个线程对它操作时,没有必要加锁,造成了性能浪费

2.乐观锁

线程访问共享变量时不加锁,当执行完后,同步值到内存时,使用旧值和内存中的值进行判断,如果相同,那么写入,如果不相同,重新使用新值执行
乐观锁适合读操作多的场景,不加锁的特点能够使其读操作的性能大幅提升。
缺点:
值相同的情况,可能被其他线程执行过
操作变量频繁时,重新执行次数多,造成性能浪费
完成比较后,写入前,被其他线程修改了值,导致不同步问题

三、Java中锁的实现

1.ReentrantLock

ReentrantLock是悲观锁,调用ReentrantLock的lock方法后,后续的代码能够一个线程执行,直到调用unlock方法

    static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        lock.lock();
        //操作共享变量
        lock.unlock();
    }
2.synchronized

使用synchronized关键字,修饰方法或者代码块,实现线程同步

    public synchronized void test() {

    }

    public void test2() {
        synchronized (this) {

        }
    }

synchronized是悲观锁,JDK1.2之前,使用的是重量级锁,后续synchronized进行了优化:
1.最初没有锁,当第一个线程访问时,升级为偏向锁

偏向锁:如果在运行过程中,同步锁只有一个线程访问,不存在多线程争用的情况,则线程是不需要触发同步的,这种情况下,就会给线程加一个偏向锁。线程第二次到达同步代码块时,会判断此时持有锁的线程是否就是自己,如果是则正常往下执行。由于之前没有释放锁,这里也就不需要重新加锁。如果自始至终使用锁的线程只有一个,很明显偏向锁几乎没有额外开销,性能极高。

2.当别的线程访问时,升级为轻量级锁,升级为轻量级锁的时候需要撤销偏向锁,撤销偏向锁的时候会导致STW(stop the word)操作
3.自旋达到次数时,升级为重量级锁,切换内核态

在对象头中存放了锁状态


对象头组成.png
3.CAS

JDK1.5后,新增java.util.concurrent包,上面我们知道乐观锁是有问题的,CAS是系统CPU提供的一种解决原子性问题的方案,解决了乐观锁的不同步问题

Java中AtomicXXX就是采用的CAS,它通过以下方法解决了乐观锁的问题
1.对对象增加版本号,每次操作时+1,而不是使用值进行是否重新执行的判断
2.自旋锁升级为重量级锁,防止一直自旋浪费cpu
3.调用compareAndSwapInt,通过jni调用原子性操作,保证多个线程都能够看到同一个变量的修改值

并发量不高以及耗时操作短时,使用CAS效率比悲观锁效率高

    static AtomicInteger atomicInteger = new AtomicInteger();

    public static void main(String[] args) {
        for(int i = 0;i<20;i++){
            new Thread(){
                @Override
                public void run() {
                    for (int j =0;j<1000;j++){
                        System.out.println(atomicInteger.incrementAndGet());
                    }
                }
            }.start();
        }
    }
4.AQS

AQS是Java提供的同步器框架,ReentrantLock、CountDownLatch等就是使用了它,当多个线程对同一对象进行操作时,内部维护一个state和等待队列,来判断是否有锁,如果没有获取到锁,那么进入等待队列,等待其他线程操作完后进行唤醒

public class VolatileTest4 {
    static CountDownLatch count = new CountDownLatch(20);

    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread() {
                @Override
                public void run() {
                    long millis = (long) (new Random().nextFloat() * 3000);
                    try {
                        Thread.sleep(millis);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count.countDown();
                    System.out.println(count.getCount() + "ms:" + millis);
                    super.run();
                }
            }.start();
        }

        try {
            count.await();
            System.out.println("所有子线程执行完毕");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

相关文章

  • Java--多线程锁机制

    上次通过三个例子,了解了Java并发三个特性,也分析了volatile不能解决原子性问题的原因,要解决原子性问题,...

  • java 多线程总结篇4——锁机制

    在开发Java多线程应用程序中,各个线程之间由于要共享资源,必须用到锁机制。Java提供了多种多线程锁机制的实现方...

  • JAVA锁机制

    在开发Java多线程应用程序中,各个线程之间由于要共享资源,必须用到锁机制。Java提供了多种多线程锁机制的实现方...

  • 2018-03-01

    随记 1.多线程锁机制之ReentrankLock可重入锁2.RabbitMQ实现消息优先级机制 概况 粗略理解为...

  • Java 中的各种锁

    多线程开发离不开各种锁,下面总结下Java和JDK提供的各种锁机制 synchronized synchroniz...

  • iOS开发中常用的几种锁

    iOS开发中常用的几种锁 简介: 操作系统在进行多线程调度的时候,为了保证多线程安全引入了锁的机制,以实现指定代码...

  • ReentrantLock (独占锁、互斥锁)

    ReentrantLock 互斥锁(独占锁) 锁 我们知道锁的基本原理是,基于将多线程并行任务通过某一种机制实现线...

  • 多线程同步

    多线程的同步依靠的是对象锁机制 加错锁(this)但是每个线程都持有this对象的对象锁 正确加锁外部创建共享资源...

  • python多线程

    python基础之多线程锁机制 GIL(全局解释器锁) GIL并不是Python的特性,它是在实现Python解析...

  • iOS多线程--并行开发二

    接上文iOS多线程--并行开发一 4、线程同步 说到多线程就不得不提多线程中的锁机制,多线程操作过程中往往多个线程...

网友评论

    本文标题:Java--多线程锁机制

    本文链接:https://www.haomeiwen.com/subject/pqxeoltx.html