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(){@Overridepublic void run(){bb.b1 = Bank.getInstance();}};Thread t2 = new Thread(){@Overridepublic 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。

        线程的生命周期:

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

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

相关文章

安卓RadioButton设置图片大小

RadioButton都不陌生,一般我们都会设置图片在里面,这就涉及一个问题,图片的大小。如果图片过大,效果很不理想。搜了很多方法,都不理想。无奈只能自己研究了 代码如下: 1,一个简单的 RadioButt…

IBM Qiskit量子机器学习速成(一)

声明:本篇笔记基于IBM Qiskit量子机器学习教程的第一节,中文版译文详见:https://blog.csdn.net/qq_33943772/article/details/129860346?spm1001.2014.3001.5501 概述 首先导入关键的包 from qiskit import QuantumCircuit from qiskit.u…

力扣138:随机链表的复制

力扣138:随机链表的复制 题目描述: 给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&#xff…

《网络协议》02. 物理层 · 数据链路层 · 网络层

title: 《网络协议》02. 物理层 数据链路层 网络层 date: 2022-08-31 22:26:48 updated: 2023-11-08 06:58:52 categories: 学习记录:网络协议 excerpt: 物理层(数据通信模型,信道)、数据链路层(封装成帧&#xff0c…

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

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

向量的点积和外积

参考:https://www.cnblogs.com/gxcdream/p/7597865.html 一、向量的内积(点乘) 定义: 两个向量a与b的内积为 ab |a||b|cos∠(a, b),特别地,0a a0 0;若a,b是非零向量,…

【性能测试】服务端中间件docker常用命令解析整理(详细)

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 1、搜索 docker …

11-08 周三 图解机器学习之实现逻辑异或,理解输出层误差和隐藏层误差项和动量因子

11-08 周三 图解机器学习之实现逻辑异或,理解输出层误差和隐藏层误差项 时间版本修改人描述2023年11月8日14:36:36V0.1宋全恒新建文档 简介 最近笔者完成了《图解机器学习》这本书的阅读,由于最近深度学习网络大行其是,所以也想要好好的弄清…

Effective C++ 系列和 C++ Core Guidelines 如何选择?

Effective C 系列和 C Core Guidelines 如何选择? 如果一定要二选一,我会选择C Core Guidelines。因为它是开源的,有300多个贡献者,而且还在不断更新,意味着它归纳总结了最新的C实践经验。最近很多小伙伴找我&#xff…

基于springboot实现智慧外贸平台系统【项目源码+论文说明】计算机毕业设计

基于springboot实现智慧外贸平台系统演示 摘要 网络的广泛应用给生活带来了十分的便利。所以把智慧外贸管理与现在网络相结合,利用java技术建设智慧外贸平台,实现智慧外贸的信息化。则对于进一步提高智慧外贸管理发展,丰富智慧外贸管理经验能…

Java进阶篇--Executors类创建常见线程池

目录 线程池架构 newSingleThreadExecutor newFixedThreadPool newCachedThreadPool newScheduledThreadPool Executors和ThreaPoolExecutor创建线程池的区别 两种提交任务的方法 线程池架构 线程池是一种线程管理的机制,用于维护和复用线程,以…

Leetcode2834. 找出美丽数组的最小和

Every day a Leetcode 题目来源:2834. 找出美丽数组的最小和 解法1:贪心 从最小正整数 1 开始枚举,设当前数为 num,如果 nums 里没有 target - num,就说明可以添加 num,依次填满直到有 n 个数即可。 用…

【k8s-1】基于docker Desktop一键式搭建k8s环境

在docker desktop中一键启动k8s环境很简单。 下面介绍如何启动dashboard,dashboard仪表盘是新手学习k8s至关重要的一个工具。 1、配置控制台 kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.1/aio/deploy/recommended.yaml 2、开…

k8s的安装部署,详细过程展示(保姆级安装教程)

k8s应用部署方式演变 在部署应用程序的方式上,主要经历了三个时代: 传统部署:互联网早期,会直接将应用程序部署在物理机上 优点:简单,不需要其它技术的参与 缺点:不能为应用程序定义资源使用…

Java面向对象(进阶)-- 面向对象特征之三:多态性

文章目录 一、多态的形式和体现(1)为什么需要多态性(polymorphism)?(2) 对象的多态性 二、 多态的理解(1)如何理解多态性(2)Java中多态性的体现(3&#xff09…

数据分析实战 | KNN算法——病例自动诊断分析

目录 一、数据及分析对象 二、目的及分析任务 三、方法及工具 四、数据读入 五、数据理解 六、数据准备 七、模型训练 八、模型评价 九、模型调参 十、模型改进 十一、模型预测 一、数据及分析对象 CSV文件——“bc_data.csv” 数据集链接:https://dow…

LeetCode146.LRU缓存

写了一个小时,终于把示例跑过了,没想到啊提交之后第19/22个测试用例没过 我把测试用例的输出复制在word上看看和我的有什么不同,没想到有18页的word,然后我一直检查终于找出了问题,而且这个bug真的太活该了&#xff0c…

Rocky Linux 配置邮件发送

Rocky Linux 配置邮件发送 使用自己的有邮箱发送 第一步-开启STMP授权 首先要开启STMP授权码,以QQ邮箱为例 第二步-下载安装包 说明一点不用命令行安装也可以,在命令行中输入会提示你是否安装s-nail,一直y即可 mail下载必须要的安装包 …

在ubuntu sudo apt-get update 更新报错

sudo apt-get update 更新报错 解决办法: 用你自己的key 根据上图自己找 sudo gpg --keyserver keyserver.ubuntu.com --recv-keys **********运行完成有一个ok 见下图 运行命令,中间的还是上面的key复制下来即可 sudo gpg --export --armor **********…

Android 多点触控

三种类型 :接力型 /配合型 /单独型 单点触控 package com.example.myapplication.viewimport android.content.Context import android.graphics.Canvas import android.graphics.Paint import android.util.AttributeSet import android.view.MotionEvent import android.vi…