多线程-线程安全的懒汉式_死锁-ReentrantLock的使用

news2024/11/30 6:57:49

线程安全的懒汉式_死锁-ReentrantLock的使用

解决单例模式中的懒汉式的线程安全问题

解决单例模式中的懒汉式的线程安全问题

> 饿汉式:不存在线程安全问题。
> 懒汉式:存在线程安全问题,(需要使用同步机制来处理)
package thread.demo04_threadsafemore.singleton;

//实现线程安全的懒汉式

import oop.demo07.B;

public class BankTest {

    static Bank b1 = null;
    static Bank b2 = null;

    public static void main(String[] args) {

        Thread t1 = new Thread(){
            @Override
            public void run() {
                b1 = Bank.getInstance();
            }
        };

        Thread t2 = new Thread(){
            @Override
            public void run() {
                b2 = Bank.getInstance();
            }
        };

        t1.start();
        t2.start();

        //这一段t1/t2.join(),为了让分线程先执行,因为这还是在主线程里面
        try {
            t1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        try {
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(b1);
        System.out.println(b2);
        System.out.println(b1 == b2);
    }
}

class Bank{

    private Bank(){}

    private static volatile Bank instance = null;


    //实现线程安全的方式1:
//    public static synchronized Bank getInstance(){  //同步监视器,默认为Book.class,类就加载一次,是唯一的
//        if (instance == null){
//
//            try {
//                Thread.sleep(100);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//
//            instance = new Bank();
//        }
//        return instance;
//    }

    //实现线程安全的方式2:
//    public static Bank getInstance(){  //同步监视器,默认为Book.class,类就加载一次,是唯一的
//        synchronized(Bank.class){
//        if (instance == null){
//
//            try {
//                Thread.sleep(100);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//
//            instance = new Bank();
//        }
//        return instance;
//    }
//        }

    //实现线程安全的方式3:相较于方式1和方式2来讲,效率更高。为了避免出现指令重排,需要将instance声明为volatile
    public static Bank getInstance() {

        if (instance == null) {
            synchronized (Bank.class) {
                if (instance == null) {

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    instance = new Bank();
                }

            }
        }
        return instance;
    }


}

单例模式饿汉式和懒汉式区别

死锁

不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程死锁。

在这里插入图片描述

【小故事】
面试官:你能解释清楚什么是死锁,我就录取你!
面试者:你录取我,我就告诉你什么是死锁!

……
恭喜你,面试通过了

一旦出现死锁,整个程序既不会发生异常,也不会给出任何提示,只是所有线程处于阻塞状态,无法继续。

举例:

package thread.demo04_threadsafemore.deadlock;

public class DeadLockTest {
    public static void main(String[] args) {

        StringBuilder s1 = new StringBuilder();
        StringBuilder s2 = new StringBuilder();

        new Thread(){

            @Override
            public void run() {

                synchronized (s1) {

                    s1.append("a");
                    s2.append("1");

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    synchronized (s2) {
                        s1.append("b");
                        s2.append("2");

                        System.out.println(s1);
                        System.out.println(s2);
                    }

                }
            }


        }.start();


        new Thread(){

            @Override
            public void run() {

                synchronized (s2) {

                    s1.append("c");
                    s2.append("3");

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    synchronized (s1) {
                        s1.append("d");
                        s2.append("4");

                        System.out.println(s1);
                        System.out.println(s2);
                    }

                }
            }


        }.start();

    }
}

诱发死锁的原因:

  • 互斥条件
  • 占用且等待
  • 不可抢夺(或不可抢占)
  • 循环等待

以上4个条件,同时出现就会触发死锁。

死锁

解决死锁:

死锁一旦出现,基本很难人为干预,只能尽量规避。可以考虑打破上面的诱发条件。

针对条件1:互斥条件基本上无法被破坏。因为线程需要通过互斥解决安全问题。

针对条件2:可以考虑一次性申请所有所需的资源,这样就不存在等待的问题。

针对条件3:占用部分资源的线程在进一步申请其他资源时,如果申请不到,就主动释放掉已经占用的资源。

针对条件4:可以将资源改为线性顺序。申请资源时,先申请序号较小的,这样避免循环等待问题。

ReentrantLock(可重入锁)的使用

除了使用synchronized同步机制处理线程安全问题之外,还可以使用jdk5.0提供的Lock锁的方式

1. 步骤:
    (1)创建Lock的实例,需要确保多个线程共用同一个Lock实例!需要考虑将此对象声明为static final。
    (2)执行lock方法,锁定对共享资源的调用。
    (3unlock()的调用,释放对共享数据的锁定。
    
	static final ReentrantLock lock = new ReentrantLock();	
	l.lock(); 
	try { 
		//需要被同步的代码(操作共享数据的代码)
    } finally { 
        l.unlock(); 
    } 


2. 面试题:
synchronized同步的方式 与Lock的对比?

synchronized不管是同步代码块还是同步方法,都需要在结束一对{}之后,释放对同步监视器的调用。
Lock是通过两个方法控制需要被同步的代码,更灵活一些。
Lock作为接口,提供了多种实现类,适合更多更复杂的场景,效率更高。

举例:

package thread.demo04_threadsafemore.lock;

//使用继承Thread类的方式,实现卖票。

import java.util.concurrent.locks.ReentrantLock;

public class LockTest {
    public static void main(String[] args) {

        SaleTicket1 s1 = new SaleTicket1("窗口1");
        SaleTicket1 s2 = new SaleTicket1("窗口2");
        SaleTicket1 s3 = new SaleTicket1("窗口3");

        s1.start();
        s2.start();
        s3.start();

    }
}


class SaleTicket1 extends Thread{

    public SaleTicket1() {
    }

    public SaleTicket1(String name) {
        super(name);
    }

    static int ticket = 100;//没有static直接300张票,每个窗口都卖1——100
    //一个对象一份的是实例变量。
    //所有对象一份的是静态变量。

    //1. 创建Lock的实例,需要确保多个线程共用同一个Lock实例!需要考虑将此对象声明为static final。
    private static final ReentrantLock lock = new ReentrantLock();//几个线程共用同一个lock,就用static,同上

    @Override
    public void run() {
        while (true){

            try {
                //2. 执行lock方法,锁定对共享资源的调用。
                lock.lock();

                if (ticket > 0) {    //这一块就是需要被同步的代码(操作共享数据的代码),前面和后面用lock.lock(); 和lock.unlock();

                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + "票号为: " + ticket);
                    ticket--;
                } else {
                    break;
                }
            }finally {
                //3. unlock()的调用,释放对共享数据的锁定。
                lock.unlock();//为了能够解锁,就要确保他必须执行,可以用try{}finally{},如果没有,就不会停止
            }

        }
    }
}

ReentrantLock的基本使用&常用方法

ReentrantLock详解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/619812.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

案例39:基于Java办公自动化管理系统开题报告设计

博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专…

Spring架构篇--2.7.3 远程通信基础--Netty原理--bind实现端口的绑定

前言:在对ServerBootstrap 进行属性赋值之后,通过bind 方法完成端口的绑定,并开始在NioEventLoop中进行轮询进行事件的处理;本文主要探究ServersocketChannel 在netty 中是如何完成注册,以及端口的绑定 1 Nio selecto…

两个月涨粉90万,B站内容风向又有新指示?

6月1日,B站公布了2023年第一季度财报。 财报中显示第一季度,B站日均活跃用户达9370万,同比增长18%。用户日均使用时长96分钟,日均视频播放量达41亿,其中,本季度B站Story-Mode竖屏视频日均播放量同比增长82…

网络安全怎么学?才不会成为脚本小子?

一,怎么入门? 1、Web 安全相关概念(2 周) 了解网络安全相关法律法规 熟悉基本概念(SQL 注入、上传、XSS、CSRF、一句话木马等)。 通过关键字(SQL 注入、上传、XSS、CSRF、一句话木马等&#…

Python使用WMI模块获取Windows系统的硬件信息,并使用pyinstaller库编译打包成exe的可执行文件

引言 今天给大家分享一篇有关Python和Windows系统的文章。你有没有想过如何获取Windows系统的硬件信息?或者你是否曾经尝试过将Python脚本编译打包成可执行文件?如果你对这些问题感兴趣,那么这篇文章一定适合你。 背景 由于公司现阶段大多…

软件兼容性测试怎么进行?兼容性测试有什么作用?

随着软件的不断更新和升级,兼容性测试也逐渐成为了软件测试的一项重要内容。那么,软件兼容性测试到底是什么?怎么进行?又有什么作用呢? 一、什么是软件兼容性测试? 软件兼容性测试是指在不同的操作系统、硬件设备、浏览器等多个环境下测试软件的可…

VulnHub项目:Hogwarts:Bellatrix

靶机地址:Hogwarts: Bellatrix ~ VulnHub 哈利波特系列~有趣~~~ 渗透过程: 首先获取靶机ip地址 对其端口探测 访问web端口,发现了小天狼星的堂姐Bellatrix Lestrange贝拉特里克斯莱斯特兰奇那个疯狂的女人!!&#x…

天涯直播筹资300万,七天仅赚14.99万,重启计划岌岌可危

我是卢松松,点点上面的头像,欢迎关注我哦! 天涯前天涯社区总编直播卖货欲筹300万,重启天涯。直播七天七夜只赚了14.99万。对于普通人来说,这收入真的是望尘莫及了,但对于天涯来说杯水车薪。 也许天涯部分…

前端工程化初体验

最近在尝试着完整地体验一下前端工程化需要的那些流程,于是自己尝试一套属于自己的前端工程化流程。 前端工程化需要做什么: 1、创建项目需要有项目模板资源,所以这里我创建了一个前端脚手架CLI工具,mfex-project,主…

Win10系统蓝屏如何使用U盘重装系统?

Win10系统蓝屏如何使用U盘重装系统?很多用户遇到了电脑系统蓝屏问题之后,都不知道怎么去进行系统重装的方法。其实系统重装没有大家想象的那么困难,以下为大家带来详细的图文教程分享。 准备工作: 1、U盘一个(尽量使用…

2023年5月CSDN客服月报|解决5个重大问题和18个次要问题,采纳1个用户建议,处理2个用户需求

听用户心声,解用户之需。hello,大家好,这里是《CSDN客诉报告》第20期,接下来就请大家一同回顾我们5月份解决的bug~ 一、重大问题 1、【商城】已支付订单权益未正常下发 反馈量:23 2、【UC】收藏/评论/账…

2023年湖北高考作文AI写

本文由 大侠(AhcaoZhu)原创,转载请声明。 链接: https://blog.csdn.net/Ahcao2008 2023年湖北高考作文AI写 🧊摘要🧊原题🧊解析🧊AIGCInsCode AI 创作助手文心一言讯飞星火 SparkDeskChatGPT3.5 🧊摘要 本文…

CANoe学习笔记一

目录 摘要 1、CANoe工程的新建 2、通过Trace工具查看交互的报文内容 3、通过Logging保存日志文件 4、创建IG发送报文 5、通过Graphics界面抓取信号波形 6、加载cdd文件 7、过滤报文ID的接收 8、其他 摘要 CANoe是德国Vector公司为汽车总线的开发而设计的一款总线开发环…

nuxt3.0学习-四、nuxt3.0的middleware(中间键)、composables(可组合物)以及Plugins(插件目录)

Nuxt3.0中间键了解地址 Nuxt提供了一个可定制的路由中间件框架,您可以在整个应用程序中使用它,非常适合在导航到特定路由之前提取要运行的代码; 路由中间件有三种: 匿名(或内联)路由中间件,直…

最佳 AI 生产力工具:更聪明地工作,而不是更努力地工作

在20世纪50年代,AI 在内存耗尽之前几乎无法完成跳棋游戏。 快进七个激动人心的十年,可以理解自然语言的人工智能系统——大型语言模型 (LLM)——正在成为我们数字工具箱中的重要工具。 在今天的文章中,我们梳理了一些提高生产力的最佳人工智…

【SpringBoot】 设置随机数据 用于测试用例

个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ 设置随机数据——常用于测试用例 SpringBoot设…

Research Day 2023:Succinct ZKP最新进展

1. 引言 主要见Ying Tong在Research Day 2023上视频分享: Advances in the Efficiency of Succinct Proofs - Ying Tong ZKP技术可用于: 1)Verifiable virtual machine:如各种zkEVM和zkVM。2)verifiable cloud com…

领跑云原生安全赛道!安全狗云甲获信通院多项荣誉认可

6月6日,ICT 中国2023高层论坛-云原生产业发展论坛在北京成功举办。 作为国内云原生安全领导厂商,安全狗受邀出席此次活动。 据悉,此次论坛主要包含论坛开幕式、成果发布、产业发展等三大部分。云原生领域领军智库、院士专家、企业高层等多位…

企业培训直播场景下嘉宾连线到底是如何实现的?

企业培训直播场景下,进行音视频连线的嘉宾,都拥有面向学员教学的权限,支持多位老师/专家异地同堂授课,那么,这种嘉宾连线到底是如何实现的? 企业培训,如何做到不受时间和地点限制,实…

数据单一触发数据库锁

【引言】 作为一名数据库开发人员或者管理员,那么你一定知道数据库锁在维护数据一致性中的作用。但是,你有没有想过,什么情况下会触发数据库锁呢? 本文将讲述一种常见的情况——数据单一触发数据库锁,并且分享如何避…