Java,多线程,线程安全的懒汉式、死锁、ReentrantLock的使用以及一些知识点补充

关于线程安全地懒汉式有以下几种方式:

/**
 * 实现线程安全的懒汉式
 */
public class BankTest
{
    Bank b1 = null;
    Bank b2 = null;
    public static void main(String[] args)
    {
        BankTest bb = new BankTest();
        Thread t1 = new Thread(){
            @Override
            public void run()
            {
                bb.b1 = Bank.getInstance();
            }
        };
        Thread t2 = new Thread(){
            @Override
            public void run()
            {
                bb.b2 = Bank.getInstance();
            }
        };


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


        try
        {
            t1.join();
        } catch (InterruptedException e)
        {
            e.getStackTrace();
        }
        try
        {
            t2.join();
        } catch (InterruptedException e)
        {
            e.getStackTrace();
        }
        System.out.println(bb.b1);
        System.out.println(bb.b2);
        System.out.println(bb.b1 == bb.b2);
    }
}


//          方式一:同步方法
//class Bank
//{
//    private Bank(){};//私有化构造器
//    private static Bank instance = null;//私有的类变量
//    //实现线程安全的方式一
//    public static synchronized Bank getInstance()//此时的同步监视器为Bank.class
//    {
//        if(instance == null)//只有当instance是非空指针时,才会创建新的对象
//        {
//            try
//            {
//                Thread.sleep(100);
//            } catch (InterruptedException e)
//            {
//                e.getStackTrace();
//            }
//            instance = new Bank();
//        }
//        return instance;
//    }
//}


//         方式二:同步代码块
//class Bank
//{
//    private Bank(){};//私有化构造器
//    private static Bank instance = null;//私有的类变量
//    //实现线程安全的方式一
//    public static Bank getInstance()
//    {
//        synchronized (Bank.class)
//        {
//            if(instance == null)//只有当instance是非空指针时,才会创建新的对象
//            {
//                try
//                {
//                    Thread.sleep(100);
//                } catch (InterruptedException e)
//                {
//                    e.getStackTrace();
//                }
//                instance = new Bank();
//            }
//            return instance;
//        }
//    }
//}


//          方式三:加了一层if,相较于方式一和方式二效率更高
//为了避免指令重排,需要将instance声明为volatile。
class Bank
{
    private Bank(){};//私有化构造器
    //私有的类变量
    private static volatile Bank instance = null;
    //实现线程安全的方式一
    public static Bank getInstance()
    {
        if(instance == null)
        {
            synchronized (Bank.class)
            {
                if (instance == null)//只有当instance是非空指针时,才会创建新的对象
                {
                    try
                    {
                        Thread.sleep(100);
                    } catch (InterruptedException e)
                    {
                        e.getStackTrace();
                    }
                    instance = new Bank();
                }


            }
        }
        return instance;//让较后的线程可以更快地拿到instance对象。
    }
}
方式三中,如果没有volatile关键字,可能会出现指令重排,当对象还未完全创建,但是已经提前return了。后面的线程判断时,未完全创建的对象也被判断为非空,对象的创建就会失败。从jdk2开始,分配空间、初始化、调用构造器会在线程的工作存储区一次性完成,然后复制到主存储区。但是需要volatile关键字,避免指令重排。
所以,要在instance的声明处加上volatile关键字。
死锁:
不同的线程分别占用对方的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。
一旦出现死锁,整个程序既不会发生异常,也不会给出任何提示,只是所有线程处于阻塞状态,无法继续。
诱发死锁的原因:
①互斥条件
②占用且等待
③不可抢夺(或不可抢占)
④循环等待(一直等待)
以上四个条件同时出现就会触发死锁。
解决死锁:
死锁一旦出现,基本很难人为干预,只能尽量规避。可以考虑打破上面的诱发条件:
针对条件①:互斥基本无法被破坏。因为线程需要通过互斥解决安全问题。
针对条件②:可以考虑一次性申请所有所需的资源,就不存在等待的问题。
针对条件③:占用部分资源的线程在进一步申请其他资源时,如果申请不到,就主动释放掉已经占用的资源。
针对条件④:可以将资源改为线性顺序。申请资源时,先申请序号较小的,这样避免循环等待问题。
除了使用synchronized同步机制处理线程安全的问题之外,还可以使用jdk5.0提供的Lock锁的方式。
步骤:
第一步,创建lock的实例,需要确保多个线程共用同一个实例,需要考虑将此对象声明为static final。
第二步,执行lock方法,锁定对共享资源的调用。
第三步,unlock的调用,释放对共享数据的锁定。
synchronized同步的方式与Lock的对比:
synchronized不管是同步代码块还是同步方法,都需要在结束一对{}之后,释放对同步监视器的调用。
Lock是通过两个方法控制需要被同步的代码,更灵活一些。
Lock作为接口,提供了多种实现类,适合更多更复杂的场景,效率更高。
Thread类的常用方法和生命周期

线程(Thread)的常用结构:

·public  Thread( ) :分配一个新的线程对象。

·public  Thread(String  name) :分配一个指定名字的新的线程对象。

·public  Thread(Runnable  target) :分配一个指定创建线程的目标对象(实现了Runnable接口的类的对象,并且该对象实现了Runnable中的run方法)。

·public  Thread(Runnable  target) :分配一个指定创建线程的目标对象并指定名字。

        线程(Thread)中的常用方法:

·start( ) :①启动线程。②调用线程的run( )方法。

·run( ) :将线程要执行的操作,声明在run中。

·currentThread( ) :获取当前执行代码对应的线程。

·getName( ) :获取线程的名称。

·setName( ) :设置线程名。

·sleep( ) :(静态方法)调用时,可以使得当前线程睡眠指定的毫秒数。

·yield( ) :(静态方法)一旦执行此方法,就释放CPU的执行权。

·join( ) :在线程a中通过线程b调用join( ),意味着线程a进入阻塞状态,直到线程b执行结束,线程a才结束阻塞状态,继续执行。

·isAlive( ) :判断当前线程是否存活。

过时方法:

①stop( ) :强制结束一个线程的执行,直接让其进入死亡状态。(不建议使用)

suspend( ) / resume( ) :暂停 / 恢复  线程的执行。(可能会造成死锁,不建议使用)

        线程的优先级:

getPriority( ) :获取线程的优先级。

setPriority( ) :设置线程的优先级。范围:[1,10]。

Thread类内部声明的三个与优先级有关的常量:

——MAX_PRIORITY(10) :最高优先级。

——MIN_PRIORITY(1) :最低优先级。

——NORM_PRIORITY(5):普通优先级,默认情况下main线程具有普通优先级。

注:优先级高并非先执行,而是有更大的概率使用CPU。

        线程的生命周期:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯算法双周赛心得——被替换的身份证(分类讨论)

大家好,我是晴天学长,分类讨论一定要细节啊,需要的小伙伴可以关注支持一下哦!后续会继续更新的。💪💪💪 1) .被替换的身份证 2) .算法思路 假设一方获胜 1.接受数据 2.假设潜梦醒 无非就是&am…

基于安卓android微信小程序的四六级助手系统

项目介绍 随着我国教育需求不断增加,高校教育资源有限,教育经费相对不足的情况下,利用现代信息技术发展高等教育,不仅充分利用了优秀的教育资源,而且为更多的人提供接受高等教育的机会,同时这也是极大促进…

【代码随想录】算法训练计划18

1、513. 找树左下角的值 题目: 给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 思路: 递归,规则,基本可以自己写出来 var maxDepth int var res int fun…

ObjectArx动态加载及卸载自定义菜单

上节中我们介绍了如何制作自定义菜单即cuix文件:给CAD中添加自定义菜单CUIX-CSDN博客https://blog.csdn.net/qianlixiaomage/article/details/134349794在此基础上,我们开发时通常需要在ObjectArx程序中进行动态的添加或者删除cuix菜单。 创建ObjectArx…

数据分析实战 | K-means算法——蛋白质消费特征分析

目录 一、数据及分析对象 二、目的及分析任务 三、方法及工具 四、数据读入 五、数据理解 六、数据准备 七、模型训练 ​编辑 八、模型评价 九、模型调参与预测 一、数据及分析对象 txt文件——“protein.txt”,主要记录了25个国家的9个属性,主…

jmeter性能测试常见的一些问题

一、request 请求超时设置 timeout 超时时间是可以手动设置的,新建一个 http 请求,在“高级”设置中找到“超时”设置,设置连接、响应时间为2000ms。 1. 请求连接超时,连不上服务器。 现象: Jmeter表现形式为&#xff…

【从0到1设计一个网关】上岸大厂的秘诀之一

文章目录 前言【从0到1设计一个网关】什么是网关?以及为什么需要自研网关?【从0到1设计一个网关】自研网关的设计要点以及架构设计【从0到1设计一个网关】自研网关的架构搭建【从0到1设计一个网关】网络通信框架Netty的设计【从0到1设计一个网关】整合Na…

Zephyr-7B论文解析及全量训练、Lora训练

文章目录 一、Zephyr:Direct Distillation of LM Alignment1.1 开发经过1.1.1 Zephyr-7B-alpha1.1.2 Zephyr-7B-beta 1.2 摘要1.3 相关工作1.4 算法1.4.1 蒸馏监督微调(dSFT)1.4.2 基于偏好的AI反馈 (AIF)1.4.3 直接蒸馏偏好优化&…

赛氪助力全国大学生数学竞赛山东赛区圆满举办

近日,全国大学生数学竞赛山东赛区比赛有序进行,赛氪已连续6年助力本项赛事蓬勃发展。在中国高等教育学会高校竞赛评估与管理体系研究专家工作组发布的《2022全国普通高校大学生竞赛分析报告》中,本赛事荣登观察目录。 全国大学生数学竞赛旨在…

Transforme原理--全局解读

文章目录 作用全局解读 作用 Transformer最初设计用于处理序列数据,特别在NLP(自然语言处理)领域取得了巨大成功 全局解读 Transformer来源于谷歌的一篇经典论文Attention is All you Need 在此使用Transformer在机器翻译中的运用来讲解Transformer。 其中Tran…

Windows11跳过联网激活 跳过登陆操作

1 背景 笔者使用VirtualBox时安装Win11,初始化的配置提示需要注册账户才能进行下一步操作,于是去查了一下发现有办法绕过,方法就是断网oobe\ByPassNRO.cmd,试了一下发现可以,便有了这篇文章。 2 流程 开机之前&…

【完美世界】石昊负伤遭囚禁,无始种惊现,二秃子用柳枝力保石昊

Hello,小伙伴们,我是小郑继续为大家深度解析国漫资讯。 深度爆料完美世界最新预告资讯,《完美世界》第137集预告片已经更新了,这一集的预告片充满了紧张的气氛和精彩的情节。从预告中我们可以看到,石昊的真实身份被天人族知晓&…

3.30每日一题(多元函数微分学)

1、判断连续:再分界点的极限值等于该点的函数值; 如何求极限值: 初步判断:分母都为二次幂开根号,所以分母为一次幂;分子为二次,一般来说整体为0; 如何说明极限为零(常用…

ZYNQ_project:IP_ram_pll_test

例化MMCM ip核,产生100Mhz,100Mhz并相位偏移180,50Mhz,25Mhz的时钟信号。 例化单口ram,并编写读写控制器,实现32个数据的写入与读出。 模块框图: 代码: module ip_top(input …

SpringBoot_01

Spring https://spring.io/ SpringBoot可以帮助我们非常快速的构建应用程序、简化开发、提高效率。 SpringBootWeb入门 需求:使用SpringBoot开发一个web应用,浏览器发起请求/hello后,给浏览器返回字符串"Hello World~~~"。 步骤…

测试人员如何通过AI提高工作效率!

随着AI技术的兴起,像OpenAI推出的ChatGPT、Microsoft发布的Microsoft 365 Copilot、阿里的通义千问、百度的文心一言、华为的盘古大模型等。很多测试人员开始担心,岗位是否会被AI取代?其实取代你的不是AI,而是会使用AI的测试人&am…

基于springboot+vue的校园闲置物品交易系统

运行环境 开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:Maven 项目介绍 本文从管…

自动驾驶学习笔记(七)——感知融合

#Apollo开发者# 学习课程的传送门如下,当您也准备学习自动驾驶时,可以和我一同前往: 《自动驾驶新人之旅》免费课程—> 传送门 《Apollo Beta宣讲和线下沙龙》免费报名—>传送门 文章目录 前言 感知融合 卡尔曼滤波 融合策略 实…

NtripShare Mos地铁自动化监测终端盒子硬件设计

自动化监测产品到目前为止做了接近一年,在软件层面上,控制终端软件、平台软件、网平差算法都已解决,硬件盒子始终是心里过不去的坎,最终还是没有耐住性子自己做了一把。 选型如下: 1、主板:瑞芯微RK3568主板。 2、外…

解决《荒野大镖客》提示emp.dll文件丢失问题,总结5个修复方法

在当今数字时代,游戏已经成为人们休闲娱乐的重要方式。作为一名游戏爱好者,笔者在近期体验《荒野大镖客》这款游戏时,遇到了一个令人苦恼的问题——emp.dll文件丢失。这个问题让游戏的无法启动进行。本文将围绕这一问题,探讨其原因…