您现在的位置是:首页 > 正文

Java --- JUC之多线程

2024-04-01 00:42:55阅读 0

目录

一、悲观锁

 二、乐观锁

三、synchronized关键字

四、公平锁与非公平锁

五、可重入锁(递归锁)

5.1、synchronized的重入的实现机理


一、悲观锁

自己在使用数据的时候一定有别的线程来修改数据,因此在获取数据的时候会先加锁,确保数据不会被别的线程修改。使用synchronized关键字和Lock的实现类都是悲观锁。

适合写操作多的场景,先加锁可以保证写操作时数据正确。显示的锁定之后再操作同步资源。

 二、乐观锁

认为自己在使用数据时不会有别的线程修改数据或资源,所以不会添加锁。

在Java中通过使用无锁编程来实现,只是在更新数据的时候去判断,之前有没有别的线程更新了这个数据。

如果这个数据没有被更新,当前线程将自己修改的数据成功写入。

如果这个数据已经被其它线程更新,则根据不同的实现方式执行不同的操作,比如放弃修改、重新枪锁等。

判断规则:1、版本号机制Version 2、最常采用的是CAS算法,Java原子类中的递增操作就通过CAS自旋实现的。

适合读操作多的场景,不加锁的特点能够使其读操作的性能大幅提升。乐观锁则直接去操作同步资源,是一种无锁算法。

三、synchronized关键字

1、作用于实例方法,当前实例加锁,进入同步代码前要获得当前实例的锁。

2、作用于代码块,对括号里配置的对象加锁。

3、作用于静态方法,当前类加锁,进去同步代码前要获得当前类对象的锁。

四、公平锁与非公平锁

公平锁:是指多个线程按照申请锁的顺序来获取锁,类似排队买票,先来的人先买后来的人在队尾排着,这是公平的  ReentrantLock lock = new ReentrantLock(true);//这里的true表示公平锁

非公平锁:指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁,在高并发环境下,有可能造成优先级翻转或者饥饿的状态(某个线程一直得不到锁)

ReentrantLock lock = new ReentrantLock();默认就是非公平锁。

为什么有公平锁与非公平锁的设计,为什么默认使用非公平锁?

1、恢复挂起的线程到真正锁的获取还是有时间差的,从开发人员来看这个时间微乎其微,但从CPU的角度来看,这个时间差存在的还是很明显的。所以非公平锁能更充分的利用CPU的时间片,尽量减少CPU空闲状态时间。

2、使用多线程很重要的考量点是线程切换的开销,当采用非公平锁时,当一个线程请求锁获取同步状态,然后释放同步状态,所以刚释放锁的线程在此刻再次获取同步状态的概率就变得非常大,所以就减少了线程的开销。

什么时候用公平?什么时候用非公平?

为了更高的吞吐量,显然非公平锁是比较合适的,因为节省很多线程切换时间,吞吐量自然就上去了,否则就使用公平锁,大家公平使用。

public class SaleTicket {


        public static void main(String[] args) {
            //创建对象
            LTicket lTicket = new LTicket();
            //创建线程
            new Thread(()->{
                for (int i = 0; i < 40; i++) {
                    lTicket.sale();
                }
            },"aa").start();
            //创建线程
            new Thread(()->{
                for (int i = 0; i < 40; i++) {
                    lTicket.sale();
                }
            },"bb").start();
            //创建线程
            new Thread(()->{
                for (int i = 0; i < 40; i++) {
                    lTicket.sale();
                }
            },"cc").start();
        }
    }

    /**
     * 创建资源类
     */
class LTicket{
        //票数
        private int number = 30;
        ReentrantLock lock = new ReentrantLock(true);
        //卖票
        public  void sale(){
            try {
                //上锁
                lock.lock();
                //判断是否有票
                if(number > 0 ){
                    System.out.println(Thread.currentThread().getName()+"卖出:"+(number--) +"剩下:"+number);
                }
            } finally { //不管是否有异常都会执行解锁
                //解锁
                lock.unlock();
            }
        }
}

五、可重入锁(递归锁)

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

在Java中ReentrantLock和synchronized都是可重入锁,可重入锁的一个优点是可一定程度上避免死锁。

5.1、synchronized的重入的实现机理

每个锁对象拥有一个锁计数器和一个指向持有该锁的线程的指针。

当执行monitorenter时,如果目标锁对象的计数器为零,那么说明它没有被其他线程持有,Java虚拟机会将该锁对象的持有线程设置为当前线程,并且将计数器加1。

在目标锁对象的计数器不为零的情况下,如果锁对象的持有线程是当前线程,那么Java虚拟机可以将其计数器加1,否则需要等待,直至持有线程释放该锁。

当执行monitorexit时,Java虚拟机则需将锁对象的计数器减1,计算器为零代表锁已被释放。

网站文章

  • 完美避坑!记一次Elasticsearch集群迁移架构实战

    完美避坑!记一次Elasticsearch集群迁移架构实战

    当有新的带有数据角色节点加入集群或者离开集群,集群会默认启动自动平衡机制,索引分片会在数据节点之间平衡漂移,达到平均分布之后停止,频繁的集群节点加入或者下线会严重影响集群的IO,影响集群响应速度,所以...

    2024-04-01 00:42:48
  • 域控制器设置计算机密码,域控服务器设置用户密码有效期

    弹性云服务器 ECS弹性云服务器(Elastic Cloud Server)是一种可随时自助获取、可弹性伸缩的云服务器,帮助用户打造可靠、安全、灵活、高效的应用环境,确保服务持久稳定运行,提升运维效率...

    2024-04-01 00:42:16
  • TCP 和 UDP 的总结

    TCP 和 UDP 的总结

    参考文章35 张图解:被问千百遍的 TCP 三次握手和四次挥手面试题什么是 TCPTCP 是面向连接的、可靠的、有序的、基于字节流的传输层通信协议。面向连接:一定是「一对一」才能连接,不能像 UDP ...

    2024-04-01 00:42:10
  • 如何在vue脚手架里面使用echarts 组件显示中国地图---亲测

    网上查阅好多资料 在 vue里面 有推荐引用1,引入 China.js文件 import echarts from 'echarts'; import 'echarts/lib/chart/map'; import 'echarts/map/js/china.js';推荐这样使用 但是做出来的效果是缩成一团的 (我已经使用百分比适应屏幕了,所以不存在没有设置宽高的问...

    2024-04-01 00:41:44
  • Arraylist 学习笔记

    /** * 比如collection接口的设计一样,可能会定义一个容器需要的相关方法,但是他在提供一个AbstractCollection的抽象方法,把相关能通用的方法进行封装实现, * 后面的容器直接继承AbstractCollection,将需要重写的方法实现,其他abstractCollection实现的方法就不用再次实现:但是注意AbstractCollection的add方法因为考...

    2024-04-01 00:41:36
  • linux saslauth用户,Linux中Postfix邮件认证配置(五)

    linux saslauth用户,Linux中Postfix邮件认证配置(五)

    原标题:Linux中Postfix邮件认证配置(五) Postfix+Dovecot+Sasl工作原理1.A用户使用MUA客户端借助smtp协议登陆smtpd服务器,需要先进行用户和密码认证,而SMT...

    2024-04-01 00:41:07
  • python基础学习(数据类型转换)

    python基础学习(数据类型转换)

    基础入门:python数据类型转换。

    2024-04-01 00:40:59
  • RFID汽车制造工业系统解决方案

    RFID汽车制造工业系统解决方案

    汽车使用寿命很长,因为不少车企为了更好的服务终端客户,也逐渐建立起跟踪车辆供应链全过程的系统,对车辆的生命周期进行管理。在第一阶段通过重复使用的标签在装配车间来监控车辆,到第二阶段,他们使用了可以抛弃...

    2024-04-01 00:40:53
  • Neurocomputing投稿记录

    Neurocomputing投稿记录

    Neurocomputing投稿记录

    2024-04-01 00:40:47
  • 怎么看android底层源码,从底层源码分析Android事件传递机制

    怎么看android底层源码,从底层源码分析Android事件传递机制

    点击一下告诉你什么是事件分发,知其然知其所以然,所以这边我篇我们就对源码展开分析!我们知道事件都是由Activity往下面分发的!但是Activity.dispatchTouchEvent()又是从被...

    2024-04-01 00:40:20