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的调用,释放对共享数据的锁定。
import java.util.concurrent.locks.ReentrantLock;public class LockTest2
{public static void main(String[] args){Window w1 = new Window("窗口一");Window w2 = new Window("窗口二");Window w3 = new Window("窗口三");w1.start();w2.start();w3.start();}
}class Window extends Thread
{public Window(){}public Window(String name){super(name);}private static int ticket = 100;//第一步,创建lock的实例,需要确保多个线程共用同一个实例,需要考虑将此对象声明为static finalprivate static final ReentrantLock ll = new ReentrantLock();@Overridepublic void run(){while(true){try{//第二步,执行lock方法,锁定对共享资源的调用ll.lock();if(ticket > 0){try{Thread.sleep(10);} catch (InterruptedException e){e.getStackTrace();}System.out.println(Thread.currentThread().getName() + "卖出一张票,票号为" + ticket);ticket--;}else{break;}}finally{//第三步,unlock的调用,释放对共享数据的锁定ll.unlock();//防止break之后不关闭锁,要将其放在finally中。}}}
}

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.hqwc.cn/news/170088.html

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

相关文章

物联网AI MicroPython学习之语法 network网络配置模块

学物联网,来万物简单IoT物联网!! network介绍 模块功能: 用于管理Wi-Fi和以太网的网络模块参考用法: import network import time nic network.WLAN(network.STA_IF) nic.active(True) if not nic.isconnected():…

.net在使用存储过程中IN参数的拼接方案,使用Join()方法

有时候拼接SQL语句时&#xff0c;可能会需要将list中的元素都加上单引号&#xff0c;并以逗号分开&#xff0c;但是Join只能简单的分开&#xff0c;没有有单引号&#xff01; 1.第一种拼接方案 List<string> arrIds new List<string>(); arrIds.Add("aa&qu…

nginx https 如何将部分路径转移到 http

nginx https 如何将部分路径转移到 http 我有一个自己的网站&#xff0c;默认是走的 https&#xff0c;其中有一个路径需要走 http。 实现 在 nginx 的配置文件 https 中添加这个路径&#xff0c;并添加一个 rewrite 的指令。 比如我需要将 tools/iphone 的路径转成 http&am…

开源:特殊的垄断

免责声明&#xff1a;本博客旨在分享我对开源策略的理解和体会&#xff0c;不代表任何组织或机构的立场或观点&#xff0c;也不构成任何商业或投资的建议或担保。本博客的内容可能存在错误或遗漏&#xff0c;也可能随着时间的推移而变得过时或不适用。请在使用或依赖本博客的内…

LeetCode(7)买卖股票的最佳时机【数组/字符串】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 121. 买卖股票的最佳时机 1.题目 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票…

通过创建自定义标签来扩展HTML

使用HTML时&#xff0c;例如&#xff0c;使用<b>标记显示粗体文本。 如果需要列表&#xff0c;则对每个列表项使用<ul>标记及其子标记<li> 。 标签由浏览器解释&#xff0c;并与CSS一起确定网页内容的显示方式以及部分内容的行为。 有时&#xff0c;仅使用一…

multilinear多项式承诺方案benchmark对比

1. 引言 前序博客有&#xff1a; Lasso、Jolt 以及 Lookup Singularity——Part 1Lasso、Jolt 以及 Lookup Singularity——Part 2深入了解LassoJolt Lasso lookup中&#xff0c;multilinear多项式承诺方案的高效性至关重要。 本文重点关注4种multilinear多项式承诺方案的实…

启动Docker服务后显示Docker Engine stopped

1、重新启动Docker服务&#xff1a;打开Windows服务管理器&#xff08;可以在开始菜单中搜索&#xff09;&#xff0c;找到"Docker Desktop Service"或类似命名的服务&#xff0c;右键单击并选择"重启"。稍等片刻&#xff0c;看看是否重新启动成功 2、尝试…

k8s二进制(ETCD的部署安装)

角色ip组件k8s-master192.168.11.169kube-apiserver,kube-controller-manager,kube-scheduler,etcdk8s-node1192.168.11.164kubelet,kube-proxy,docker,etcdk8s-node2192.168.11.166kubelet,kube-proxy,docker,etcd 1、为etcd签发证书 1、证书的下载(任意机器上执行都可以) …

深度解剖Linux权限的概念

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;牢记Linux权限的概念。 > 毒鸡汤&#xff1a;你…

Java13新增特性

前言 前面的文章&#xff0c;我们对Java9、Java10、Java11、Java12 的特性进行了介绍&#xff0c;对应的文章如下 Java9新增特性 Java10新增特性 Java11新增特性 Java12新增特性 今天我们来一起看一下Java13这个版本的一些重要信息 版本介绍 Java 13 是在 2019 年 9 月 17 日…

SSM框架Demo: 简朴博客系统

文章目录 1. 前端页面效果2. 项目创建3. 前期配置3.1. 创建数据库数据表3.2. 配置文件 4. 创建实体类5. 统一处理5.1. 统一返回格式处理5.2. 统一异常处理 6. 全局变量7. Session工具类8. 登录拦截器9. 密码加盐加密10. 线程池组件11. dao层11.1. UserMapper11.2. ArticleMappe…