JAVA中实现多线程-单例双重锁(DCL(Double Check Lock)双重锁检查)

news2024/11/19 23:32:02

一 .多线程

  1. 继承 Thread 类
  2. 实现 Runnable 接口
  3. 实现 Callable 接口
  4. 线程池

重写run方法,创建对象,调用start()方法启动线程

在这里插入图片描述
1,新生状态

– 用new关键字建立一个线程后,该线程对象就处于新生状态。

– 处于新生状态的线程有自己的内存空间,通过调用start()方法进入就绪状态。

2,就绪状态

– 处于就绪状态线程具备了运行条件,但还没分配到CPU,处于线程就绪队列,等待系统为其分
配CPU。

– 当系统选定一个等待执行的线程后,它就会从就绪状态进入执行状态,该动作称为 CPU “ 调 度”。

3,运行状态

– 在运行状态的线程执行自己的run方法中代码,直到等待某资源而阻塞戒完成任何而死亡。

– 如果在给定的时间片内没有执行结束,就会被系统给换下来回到等待执行状态。

4,阻塞状态

– 处于运行状态的线程在某些情况下,如执行了sleep(睡眠)方法,戒等待I/O设备等资源,将让
出CPU并暂时停止自己运行,进入阻塞状态。

– 在阻塞状态的线程不能进入就绪队列。只有当引起阻塞的原因消除时,如睡眠时间已到,戒等
待的I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后从
原来停止的位置开始继续执行。

5,死亡状态

– 死亡状态是线程生命周期中的最后一个阶段。线程死亡的原因有三个,

一个是正常运行的线程完成了它的全部工作;

另一个是线程被强制性地终止,如通过stop方法来终止一个线程【不推荐使用】;

三是线程抛出未捕获的异常。

6,线程操作的相关方法

在这里插入图片描述

7,阻塞状态(sleep/yield/join方法)

1,有三种方法可以暂停Thread执行

(1),sleep
不会释放锁,Sleep时别的线程也不可以访问锁定对象。

(2),yield:
让出CPU的使用权,从运行态直接迚入就绪态。让CPU重新挑选哪一个线程进入运行状态。

(3),join:
当某个线程等待另一个线程执行结束后,才继续执行时,使调用该方法的线程在此之前执行完毕,也就是等待调用该方法的线程执行完毕后再往下继续执行

一、继承 Thread 类

  1. 创建 MyThread 类,让其继承 Thread 类并重写 run() 方法。
  2. 创建 MyThread 类的实例对象,即创建一个新线程。
  3. 调用 start() 方法,启动线程。
public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("我是通过继承 Thread 类创建的多线程,我叫" + Thread.currentThread().getName());
    }
}

class TestMyThread {
    public static void main(String[] args) {
        MyThread myThread1 = new MyThread();
        myThread1.setName("Thread-1");
        MyThread myThread2 = new MyThread();
        myThread2.setName("Thread-2");
        MyThread myThread3 = new MyThread();
        myThread3.setName("Thread-3");

        myThread1.start();
        myThread2.start();
        myThread3.start();
    }
}

线程的执行顺序和代码中编写的顺序没有关系,线程的执行顺序是具有随机性的。

二、实现 Runnable 接口

Runnable 接口只有一个 run() 方法,源码如下:

public interface Runnable {
    public abstract void run();
}
  1. 创建 MyRunnable 类实现 Runnable 接口。
  2. 创建 MyRunnable 类的实例对象 myRunnable 。
  3. 把实例对象 myRunnable 作为参数来创建 Thread 类的实例对象 thread,实例对象 thread 就是一个新线程。
  4. 调用 start() 方法,启动线程。
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("我是通过实现 Runnable 接口创建的多线程,我叫" + Thread.currentThread().getName());
    }
}

class TestMyRunnable {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}

相比于继承 Thread 类的方法来说,实现 Runnable 接口是一个更好地选择,因为 Java 不支持多继承,但是可以实现多个接口。

有一点值得注意的是 Thread 类也实现了 Runnable 接口,这意味着构造函数 Thread(Runnable target) 不仅可以传入 Runnable 接口的对象,而且可以传入一个 Thread 类的对象,这样就可以将一个 Thread 对象中的 run() 方法交由其他线程进行调用。

三、线程池

Java通过Executors创建线程池,分别为:

1.Executors.newCachedThreadPool()
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程, 适用于服务器负载较轻,执行很多短期异步任务

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

2,Executors.newFixedThreadPool(3)
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待,适用于可以预测线程数量的业务中,或者服务器负载较重,对当前线程数量进行限制。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

线程池核心的参数:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }

  1. corePoolSize 线程池核心线程大小
  2. maximumPoolSize 线程池最大线程数量
  3. keepAliveTime空闲线程存活时间
  4. unit 空闲线程存活时间单位
  5. workQueue 工作队列
  6. threadFactory 线程工厂
  7. handler 拒绝策略

线程池四种拒绝任务策略
1、直接丢弃(DiscardPolicy)

2、丢弃队列中最早的任务(DiscardOldestPolicy)。

3、抛异常(AbortPolicy)

4、将任务分给调用线程来执行(CallerRunsPolicy)。

应用举例:

一个火车站购票系统,有100张车票,由多个窗口售卖,直到卖完为止,这时程序中,需要使用到多线程,如果不对其进行限制的话,就会出现同一个座位卖两张票的情况。

单线程:简单来说,就是一个窗口售卖100张票
多线程:多个窗口,同事售卖100张票。

二.单例双重锁

描述
为了保证线程的安全性,往往要以牺牲性能为代价。为了兼得二者,前人进行了多番尝试,也确实创造出诸多有效方案,双重检查锁就是其中的一种。

DCL:Double Check Lock(双重检查锁)。令人哭笑不得的是,其闻名原因不是因为有效性,而是行业标杆级的错误性。双重检查锁同时体现了同步中的独占性与可见性同等的重要性,因此成为多线程学习中必学的经典案例。

为什么需要第二次检查?

首先我们来分析没有第二次检查的情况:当userBean为null时,两个线程可以并发地进入if语句内部。 然后,一个线程进入synchronized块来初始化userBean,而另一个线程则被阻断。当第一个线程退出synchronized块时,等待着的线程进入并创建另一个DBHelper对象。当第二个线程进入 synchronized 块时,它并没有检查 instance 是否非 null。因此我们需要对instance进行第二次非空检查,这也是“双重检查加锁”名称的由来。

例子

public class UserBean {

    private static UserBean userBean=null;

    private UserBean() {
    }

    //线程锁
    public static UserBean getInstance(){


        /** 采用双重检查加锁实例化单件*/
        //第一次检查
        if (Objects.isNull(userBean)){
            synchronized (UserBean.class){
                //第二次检查
                if (Objects.isNull(userBean)){
                    userBean=new UserBean();
                }
            }
        }

        return userBean;
    }
}

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

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

相关文章

Netty前置知识

传统IO 这里以文件输入输出流&#xff1a;FileInputStream 、 FileOutputStream 来进行解释。由继承关系得知&#xff0c;这两个输入和输出类继承自 InputStream 和 OutputStream 这两个基础的输入、输出的抽象类&#xff0c;这时我们可以看到当我们需要读写文件的时候&#x…

leetcode--搜索

搜索1.深度优先搜索(DFS)&#xff08;1&#xff09;岛屿的最大面积(695)&#xff08;2&#xff09;省份数量&#xff08;3&#xff09;太平洋大西洋水流问题(417)2.回溯法&#xff08;1&#xff09;全排列(46)&#xff08;2&#xff09;组合(77)&#xff08;3&#xff09;单词搜…

C++ allocator设计内存管理器

文章目录allocator内存管理器基本属性类的设计关键功能的实现完整的内存管理器内存管理器的测试&#xff1a;设计自定义的String类。前情回顾&#xff1a; allocator内存管理类 allocator内存管理器 某些类需要在运行时分配可变大小的内存空间&#xff0c;一般来说我们使用容器…

从零搭建完整python自动化测试框架(UI自动化和接口自动化)

从零搭建完整python自动化测试框架&#xff08;UI自动化和接口自动化&#xff09; 文章目录 总体框架 PO模式、DDT数据驱动、关键字驱动 框架技术选择 框架运行结果 各用例对应的定义方式&#xff08;PO/DDT&#xff09; 测试执行结果 从零开始搭建项目 一、开发环境搭…

泪目,终于有P8大佬把困扰我多年的《计算机网络原理》全部讲明白了

前言 为什么网络协议这么重要呢&#xff1f;集群规模一大&#xff0c;我们首先想到的就是网络互通的问题&#xff1b;应用吞吐量压不上去&#xff0c;我们首先想到的也是网络互通的问题。所以&#xff0c;要成为技术牛人&#xff0c;搞定大系统&#xff0c;一定要过网络这一关&…

Mac怎么清理缓存?这两种方法都非常好用哦

与电脑系统或应用程序非常相似&#xff0c;您的Mac也有自己的系统缓存&#xff0c;它可以在后台临时存储数据&#xff0c;以加快软件安装速度并减少互联网数据使用量&#xff08;通过Apple&#xff09;。与电脑系统或应用程序类似&#xff0c;缓存数据可能会开始堆积——占用存…

unordered系列关联式容器以及哈希表原理实现

Ⅰ. unordered 系列关联式容器 在C98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时效率可达到 log2nlog_2 nlog2​n&#xff0c;即最差情况下需要比较红黑树的高度次&#xff0c;当树中的节点非常多时&#xff0c;查询效率也不理想。最好的…

Android Studio Profiler 检查内存

Android Studio Profiler 检查内存简单介绍 如何使用&#xff1f; 第一步&#xff1a;点击Profiler按钮 第二步&#xff1a;选择 第三步&#xff1a;选择Capture heap dump 并点击Record 解释相关按钮的功能 垃圾桶按钮&#xff1a;用于强制执行垃圾回收事件的按钮&#xff…

LinkedList(JDK1.8)源码+底层数据结构分析

文章目录前言一、双向链表1.1 双向链表示意图1.2 LinkedList 属性1.3 Node 节点对象二、双向链表的操作2.1 添加元素-add2.2 删除元素-remove2.3 修改元素-set2.4 查询元素-get前言 双向链表是一种数据结构&#xff0c;由若干个节点构成&#xff0c;其中每个节点均由三部分构成…

疯狂游戏笔试题-2022秋招

编程题 1.假设数组第一个元素是k, 如果k在数组内, 则k*21 和 k*31也在数组内. 在已知k的情况下, 需算出另一个数是否也在数组内? 例子: 输入1,2 输出False 输入1,4 输出True 解题思路&#xff1a;暴力&#xff08;doge&#xff09;,实在想不到其它好方法&#xff0c;有…

生成模型详解

一、生成模型的定义 给定的训练集X{x1,x2,...,xn}X \{x^1,x^2,...,x^n\}X{x1,x2,...,xn}隐变量zzz满足p(z)N(0,I)p(z) \mathcal{N} (0,I)p(z)N(0,I)定义一个条件分布pθ(x∣z)p_{\theta}(x|z)pθ​(x∣z)&#xff0c;θ\thetaθ可以理解为生成模型的参数训练好模型后&#xff…

java高校宿舍费缴纳报修管理系统ssm1561

系统选用B/S模式&#xff0c;应用jsp技术&#xff0c; MySQL为后台数据库。系统主要包括个人中心、学生管理、宿管管理、宿舍信息管理、宿舍预订管理&#xff0c;在线报修管理、费用缴纳管理、投诉建议管理、论坛交流、系统管理等功能模块。 本系统采用从上往下的步骤开发&…

爬虫学习-数据解析三种方式:正则、bs4、xpath,以及一些实例操作

若出现乱码page_text page_text.encode(iso-8859-1).decode(gbk)或者查看源码head里面的说明&#xff0c;设置成相同的即可 数据解析原理概述 解析的局部的文本内容都会在标签之间或者标签对应的属性中进行储存数据解析就是 1、进行指定标签的定位2、标签或者标签对应的属性中…

设计模式之美总结(结构型篇)

title: 设计模式之美总结&#xff08;结构型篇&#xff09; date: 2022-12-21 09:59:11 tags: 设计模式 categories:设计模式 cover: https://cover.png feature: false 文章目录1. 代理模式&#xff08;Proxy Design Pattern&#xff09;1.1 原理解析1.2 动态代理1.3 应用场景…

排查Java服务CPU使用率高达100%的原因

排查Java服务CPU使用率高达100%的原因 Java服务在服务器运行一段时间&#xff0c;有一天CPU使用率突然高达100%&#xff0c;通过jstack工具分别在CPU使用率为100%时执行了一次堆线程dump和cpu使用率降下来后执行了一次堆线程dump 目录排查Java服务CPU使用率高达100%的原因一、环…

【SQL】一文详解嵌入式SQL(建议收藏)

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后…

SQLMap 扫描利用SQL注入

一、SQLMap介绍 SQLMap 是一个自动化的SQL注入工具&#xff0c;其主要功能是扫描、发现并利用给定URL的SQL注入漏洞&#xff0c;内置了很多绕过插件&#xff0c;支持的数据库是MySQL 、Oracle 、PostgreSQL 、Microsoft SQL Server、Microsoft Access 、IBM DB2, SQ Lite 、Fir…

光伏行业管理亟待变革,数商云供应链系统订单流程自动化流转助力企业降本增效

作为实现“3060”双碳目标的主力军&#xff0c;光伏产业正迎来空前的政策、市场、资本三重加持的红利期。有业内人士预测&#xff0c;到2025年全球新增光伏装机量将达到270-330GW&#xff0c;国内新增光伏装机量将达到90-110GW&#xff0c;十四五期间年均新增光伏装机量将达到7…

用React做一个音乐播放器

介绍 任何正在学习 React 并想使用 React 构建项目的人。有各种博客和文章可以为开发人员指导此类项目。我确实浏览过这些文章&#xff0c;但其中总是缺少一种项目。缺少的项目是音乐播放器和视频播放器。这两个项目都会让您有机会处理音频和视频。您将学到很多东西&#xff0…

Linux学习-97-vmware网络桥接模式配置和vmware快照操作

19.3 vmware网络桥接模式配置 桥接&#xff1a;需要保证Linux虚拟机和本机处在同一个网段&#xff01; #win平台输入ipconfig查看主机的ip地址Linux也必须要配置到对应的网段 桥接模式&#xff1a;主机ip 和虚拟机ip映射到同一块物理网卡&#xff08;光纤&#xff0c;无线…