JUC并发编程(二)

news2024/9/23 9:29:33

一、过时方法

一些不推荐使用的方法已经过时,容易破坏同步代码块,使对象的锁得不到释放,进而造成线程死锁
在这里插入图片描述

二、守护线程

默认情况下,Java 进程需要等待所有线程都运行结束,才会结束。有一种特殊的线程叫做守护线程,只要其它非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束。

正常情况下:主线程运行结束,但t1线程仍未结束,因此进程并不会结束(只要有一个线程还在运行,Java进程并不会结束
在这里插入图片描述

将t1设置为守护线程后

import lombok.extern.slf4j.Slf4j;

@Slf4j(topic = "c.Test15")
public class Test15 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (true) {
                if (Thread.currentThread().isInterrupted()) {
                    break;
                }
            }
            log.debug("结束");
        }, "t1");
        // 将t1设置为守护线程(默认值为非守护线程:false)
        t1.setDaemon(true);   
        t1.start();

        Thread.sleep(1000);
        log.debug("结束");
    }
}

运行结果:主线程(非守护)运行结束后,无论守护线程(t1)是否执行完毕均会强制结束
在这里插入图片描述

守护线程应用
● 垃圾回收器线程就是一种守护线程【再堆内存中分配的对象,当没有其它对象引用这些对象时,这些未被引用的对象就会定期被垃圾回收
● Tomcat 中的 Acceptor 和 Poller 线程都是守护线程,所以 Tomcat 接收到 shutdown 命令后,不会等待它们处理完当前请求

三、线程状态(五种)

五种状态,这是从 操作系统 层面来描述的
在这里插入图片描述
初始状态】仅是在语言层面创建了线程对象,还未与操作系统线程关联(egJava中newThread对象,但未调用其start()方法

● 【可运行状态】(就绪状态)指该线程已经被创建(与操作系统线程关联),可以由 CPU 调度执行,但暂时还未获得CPU的时间片

● 【运行状态】指获取了 CPU 时间片运行中的状态
—— 当 CPU 时间片用完,会从【运行状态】转换至【可运行状态】,其切换会导致线程的上下文切换

● 【阻塞状态
—— 如果调用了阻塞 API,如 BIO 读写文件,这时该线程实际不会用到 CPU(调度器不会考虑调度阻塞状态的线程),会导致线程上下文切换,进入【阻塞状态】
—— 等 BIO 操作完毕,会由操作系统唤醒阻塞的线程,转换至【可运行状态】
—— 与【可运行状态】的区别是,对【阻塞状态】的线程来说只要它们一直不唤醒,调度器就一直不会考虑调度它们

● 【终止状态】表示线程已经执行完毕,生命周期已经结束,不会再转换为其它状态

四、线程状态(六种)

六种状态,是从Java API层面来描述的

根据Thread.State枚举,分为六种状态
在这里插入图片描述
NEW 线程刚被创建,但是还没有调用 start() 方法

RUNNABLE 当调用了 start() 方法之后,注意,Java API 层面的 RUNNABLE 状态涵盖了 操作系统 层面的【可运行状态】、【运行状态】和【阻塞状态】(由于 BIO 导致的线程阻塞,在 Java 里无法区分,仍然认为是可运行)操作系统层面的阻塞状态在Java中还是RUNNABLE

BLOCKED WAITINGTIMED_WAITING 都是 Java API 层面对【阻塞状态】的细分,后面会在状态转换一节详述

TERMINATED 当线程代码运行结束

3.1 六种状态演示

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;

@Slf4j(topic = "c.TestState")
public class TestState {
    public static void main(String[] args) throws IOException {

        // ① 并未调用线程1的start()方法===>NEW
        Thread t1 = new Thread("t1") {
            @Override
            public void run() {
                log.debug("running...");
            }
        };

        // ② 不断运行===>RUNNABLE(既有可能分到时间片也有可能为分到时间片,也有可能陷入操作系统的IO阻塞)
        Thread t2 = new Thread("t2") {
            @Override
            public void run() {
                while(true) { // runnable

                }
            }
        };
        t2.start();

        // ③ 打印后执行完毕===>TERMINATED
        Thread t3 = new Thread("t3") {
            @Override
            public void run() {
                log.debug("running...");
            }
        };
        t3.start();

        // ④ 线程处于阻塞状态【sleep时间足够长===>TIMED_WAITING(有时限的的等待)】
        Thread t4 = new Thread("t4") {
            @Override
            public void run() {
                synchronized (TestState.class) {
                    try {
                        Thread.sleep(1000000); // timed_waiting
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t4.start();

        // ⑤ 等待t2(死循环)一直运行结束===>WAITING(没有时限的等待)
        Thread t5 = new Thread("t5") {
            @Override
            public void run() {
                try {
                    t2.join(); // waiting
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        t5.start();

        // ⑥ t4线程会先对对象加锁,t6线程不能获取对象的锁===>t6陷入BLOCKED
        Thread t6 = new Thread("t6") {
            @Override
            public void run() {
                synchronized (TestState.class) { // blocked
                    try {
                        Thread.sleep(1000000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t6.start();

        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.debug("t1 state {}", t1.getState());
        log.debug("t2 state {}", t2.getState());
        log.debug("t3 state {}", t3.getState());
        log.debug("t4 state {}", t4.getState());
        log.debug("t5 state {}", t5.getState());
        log.debug("t6 state {}", t6.getState());
        System.in.read();
    }
}

运行结果:
在这里插入图片描述

四、多线程应用统筹分析

如何使用多线程得到最优方案?
在这里插入图片描述
后两种办法均耗费时间较长
在这里插入图片描述
上图可以一眼看出,办法甲总共要16分钟(而办法乙、丙需要20分钟)。因此合理分配便可节约大量时间,我们可以使用多线程的思想便可找到最优的方案
在这里插入图片描述
方案实现:

import lombok.extern.slf4j.Slf4j;

import static cn.itcast.n2.util.Sleeper.sleep;

@Slf4j(topic = "c.Test16")
public class Test16 {

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            log.debug("洗水壶");
            sleep(1);
            log.debug("烧开水");
            sleep(5);
        },"老王");

        Thread t2 = new Thread(() -> {
            log.debug("洗茶壶");
            sleep(1);
            log.debug("洗茶杯");
            sleep(2);
            log.debug("拿茶叶");
            sleep(1);
            try {
                t1.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("泡茶");
        },"小王");

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

运行结果:
在这里插入图片描述

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

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

相关文章

spring中BeanFactory 和ApplicationContext

在学习spring的高阶内容时,我们有必要先回顾一下spring回顾spring1.什么是springspring是轻量级的,指核心jar包时很小的;非侵入式的一站式框架(数据持久层,web层,核心aop),为了简化企业级开发。核心是IOC&a…

Python自动化测试实战篇(6)用PO分层模式及思想,优化unittest+ddt+yaml+request登录接口自动化测试

这些是之前的文章,里面有一些基础的知识点在前面由于前面已经有写过,所以这一篇就不再详细对之前的内容进行描述 Python自动化测试实战篇(1)读取xlsx中账户密码,unittest框架实现通过requests接口post登录网站请求&…

计算及网络第一章

计算机网络-第一章 概述 文章目录计算机网络-第一章 概述计算机网络在信息时代中的作用互联网概述网络的网络互联网的组成网络的边缘部分互联网的核心部分电路交换的主要特点分组交换的主要特点计算机网络的类别几种不同类别的计算机网络计算及网络的性能计算机网络的性能指标计…

面向对象之-接口鉴权

1 需求 1.1 需求背景 为了保证接口调用的安全性,我们希望设计实现一个接口调用鉴权功能,只有经过认证之后的系统才能调用我们的接口,没有认证过的系统调用我们的接口会被拒绝。 2 需求分析 2.1 基础分析 对于如何做鉴权这样一个问题&…

配置 Haproxy 负载均衡群集

配置 haproxy 负载均衡群集 🏆荣誉认证:51CTO博客专家博主、TOP红人、明日之星;阿里云开发者社区专家博主、技术博主、星级博主。 💻微信公众号:微笑的段嘉许 📌本文由微笑的段嘉许原创! &#…

Android 基础知识4-3.3 Button(按钮)与ImageButton(图像按钮)详解

一、引言 今天给大家介绍的Android基本控件中的两个按钮控件,Button普通按钮和ImageButton图像按钮; 其实ImageButton和Button的用法基本类似,至于与图片相关的则和后面ImageView相同,所以本节 只对Button进行讲解,另外…

MySQL进阶之锁

锁是计算机中协调多个进程或线程并发访问资源的一种机制。在数据库中,除了传统的计算资源竞争之外,数据也是一种提供给许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决堆的一个问题,锁冲突也是影响数据…

Neo4j列表函数

使用列表 标量列表函数 size() 函数返回列表中的元素的数量 MATCH (p:Person)-[:ACTED_IN]->(m:Movie) WITH p, collect (m.title) AS MovieTitles WITH p, MovieTitles, size(MovieTitles) AS NumMovies WHERE NumMovies > 20 RETURN p.name AS Actor, NumMovies, Movie…

浙大PTA拼题A读者验证码刷题页面、PTA免费刷题页面(不需要读者验证码)

有一个B站号李桥桉,很多年前讲过PTA里的一些题目的解法。近两年有好多同学反馈,需要读者码才能进行答题,不然只能免费注册、看题、编写代码,就是不能提交代码(大受震撼)。 咱就是说,会不会是同学们找错页面了&#xff…

【数据库】第十二章 数据库管理

第12章 数据库管理 数据库的物理存储 关于内存、外存、磁盘、硬盘、软盘、光盘的区别_Allenzyg的博客-CSDN博客_磁盘和硬盘的区别 数据库记录在磁盘上的存储 定长,变长跨块,非跨快 文件的组织方方法: 无序记录文件(堆文件heap或pile file…

eddsa 算法

信息安全课程设计:eddsa 算法 一、项目要求 使用 C 语言开发;可以实现公私钥生成、签名、认证;只需要手动输入明文,代码会自动生成公私钥、签名、认证;记录公私钥生成、签名、认证的时间;在 VS 上运行&am…

React useCallback如何使其性能最大化?

前言 React中最让人畅谈的就是其带来的灵活性,可以说写起来非常的舒服。但是也就是它的灵活性太强,往往让我们忽略了很多细节的地方,而就是这些细节的东西能进行优化,减小我们的性能开销。可以说刚学React和工作几年后写React的代…

JVM内存结构之堆(重要)

1、概述每个JVM进程有且只有一个堆,进程内的所有线程共享这块区域,堆区在JVM启动的时候即被创建,其空间大小也就确定了,是JVM内存结构中最大的一块区域。由于线程共享,堆也就成了JVM内存管理的核心区域。《Java虚拟机规…

热爱所有热爱

想成为这样的一个人,在工作中是一名充满极客精神的Programmer,处理遇到的问题能够游刃有余,能够做出优雅的设计,写出一手优秀的代码,还有着充分的学习能力和业务能力,做一名职场中的佼佼者。 在工作之余还能…

15、条件概率、全概率公式、贝叶斯公式、马尔科夫链

条件概率定义:设A、B是两个事件,且,P(A) > 0 则称 为事件A发生的条件下事件B的条件概率对这个式子进行变形,即可得到概率的乘法公式:P(A) > 0 时,则P(B) > 0 时,则乍一看,…

数字化转型导师坚鹏:BLM农商行数字化转型实战解决方案及案例

BLM农商行数字化转型实战解决方案及案例研究 ——以BLM模型为核心,践行知行合一思想,实现知行果合一 课程背景: 很多农商行存在以下问题: 不知道如何开展数字化转型工作? 不清楚农商行数字化转型方法论? …

Python—单分支结构

&#xff08;1&#xff09;if分支语句 Python中if语句的语法结构&#xff1a; if <条件表达式>&#xff1a;    满足条件运行的代码1    满足条件运行的代码2 代码示例&#xff1a; age 12 if age > 18:print(去上网)if 1 1 2 and :print(我满足条件了)if 1 …

【C++】C++入门(下)

引用 什么是引用&#xff1f;   引用是给一个已经存在的变量取一个别名&#xff0c;在语法上并不会给这个别名开一个空间&#xff0c;它和她引用的变量共用一个空间。但是实际上引用也是开了一块空间的&#xff0c;用来存放引用名。引用是按照指针的方式来实现的。引用语法&…

电子技术——B类输出阶

电子技术——B类输出阶 下图展示了一个B类输出阶的原理图&#xff0c;B类输出阶由两个互补的BJT组成&#xff0c;不同时导通。 原理 当输入电压 vI0v_I 0vI​0 的时候&#xff0c;两个晶体管都截止输出电压为零。当 vIv_IvI​ 上升至超过0.5V的时候&#xff0c;此时 QNQ_NQN…

MVVM 架构进阶:MVI 架构详解

前言Android开发发展到今天已经相当成熟了&#xff0c;各种架构大家也都耳熟能详&#xff0c;如MVC,MVP,MVVM等&#xff0c;其中MVVM更是被官方推荐&#xff0c;成为Android开发中的显学。不过软件开发中没有银弹&#xff0c;MVVM架构也不是尽善尽美的&#xff0c;在使用过程中…