Java多线程核心技术第一阶段-Java多线程基础 02

news2024/11/16 11:47:30

接上篇:Java多线程核心技术第一阶段-Java多线程基础 01

3.3 清除中断状态的使用场景

        this.interrupted()方法具有清除状态标志值的功能,借用此特性可以实现一些效果。

【示例3.3.1】在MyThread4线程中向list1和list2存放数据,基于单一职责原则,MyThread4线程只负责存放数据,不负责处理存放的数据量,数据量由main线程进行处理。

public class Box {
    public static ArrayList list1 = new ArrayList();
    public static ArrayList list2 = new ArrayList();
}
public class MyThread extends Thread{

    @Override
    public void run() {
        try {
            while (true) {
                if (Thread.interrupted()) {
                    throw new InterruptedException("线程中断");
                }
                for (int i = 0; i < 10000; i++) {
                    new String("" + Math.random());
                }
                Box.list1.add("数据A");
                System.out.println("list1 size = " + Box.list1.size());
            }
        } catch (InterruptedException exception) {
            exception.printStackTrace();
        }
        try {
            while (true) {
                if (Thread.interrupted()) {
                    throw new InterruptedException("线程中断");
                }
                for (int i = 0; i < 10000; i++) {
                    new String("" + Math.random());
                }
                Box.list2.add("数据B");
                System.out.println("list2 size = " + Box.list2.size());
            }
        } catch (InterruptedException exception) {
            exception.printStackTrace();
        }
    }
}
public class Run1 {
    public static void main(String[] args) throws InterruptedException {
        MyThread myThread = new MyThread();
        myThread.start();
        boolean list1Isinterrupt = false;
        boolean list2Isinterrupt = false;
        while(myThread.isAlive()){
            if(Box.list1.size() > 500 && list1Isinterrupt == false){
                myThread.interrupt();
                list1Isinterrupt = false;
            }
            if(Box.list1.size() > 600 && list1Isinterrupt == false){
                myThread.interrupt();
                list2Isinterrupt = false;
            }
            Thread.sleep(100);

        }
    }
}

3.4 能停止的线程-异常法

        根据前面的介绍,只需要通过线程中的for语句来判断线程是否是停止状态即可判断后面的代码是否可运行,如果是停止状态,则后面的代码不在运行。

【示例3.4.1】

public class MyThread extends Thread{
    @Override
    public void run(){
        for (int i = 0; i < 500000; i++) {
            if(MyThread.interrupted()){
                System.out.println("这已经是停止状态了,我要退出了");
                break;
            }
            System.out.println("i = " + (i+1));
        }
    }
}
public class Run1 {
    public static void main(String[] args) {
        try {
            MyThread myThread = new MyThread();
            myThread.start();
            Thread.sleep(100);
            myThread.interrupt();
        }catch (InterruptedException e){
            System.out.println("main catch");
            e.printStackTrace();
        }
    }
}

        上面的示例中,虽然停止了线程,但是如果for语句下面还有语句,那么程序还会继续执行。

【示例】 

public class MyThread1 extends Thread{
    @Override
    public void run(){
        for (int i = 0; i < 500000; i++) {
            if(MyThread1.interrupted()){
                System.out.println("这已经是停止状态了,我要退出了");
                break;
            }
            System.out.println("i = " + (i+1));
        }
        System.out.println("此行被输出,如果此行代码时for又继续执行,线程并未停止");
    }
}
public class Run1 {
    public static void main(String[] args) {
        try {
            MyThread1 myThread = new MyThread1();
            myThread.start();
            Thread.sleep(100);
            myThread.interrupt();
        }catch (InterruptedException e){
            System.out.println("main catch");
            e.printStackTrace();
        }
    }
}

如何解决语句继续运行的问题呢?看一下更新后的代码:

public class MyThread1 extends Thread{
    @Override
    public void run(){
        super.run();
        try{
            for (int i = 0; i < 500000; i++) {
                if(MyThread1.interrupted()){
                    System.out.println("这里是停止状态,退出!");
                    throw  new InterruptedException();
                }
                System.out.println("i = " + (i + 1));
            }
        }catch (InterruptedException e){
            System.out.println("MyThread1 线程 被catch了");
            e.printStackTrace();
        }
    }
}

public class Run1 {
    public static void main(String[] args) {
        try {
            MyThread1 myThread = new MyThread1();
            myThread.start();
            Thread.sleep(100);
            myThread.interrupt();
        }catch (InterruptedException e){
            System.out.println("main catch");
            e.printStackTrace();
        }
        System.out.println("end!");
    }
}

4 暂停线程

4.1 使用suspend()暂停线程

        暂停线程意味着此线程还可以恢复运行,在Java多线程中可以使用suspend()方法暂停线程,使用resume()方法来恢复线程。

【示例4.1】 

public class MyThread1 extends Thread{
    private long i = 0;

    public long getI() {
        return i;
    }

    public void setI(long i) {
        this.i = i;
    }

    @Override
    public void run(){
        while(true){
            i++;
        }
    }
}
public class Run1 {
    public static void main(String[] args) {
        try{
            MyThread1 thread = new MyThread1();
            thread.start();
            Thread.sleep(5000);
            //A段
            thread.suspend();
            System.out.println("A = " + System.currentTimeMillis() + " i ="+ thread.getI());
            Thread.sleep(5000);
            System.out.println("A = " + System.currentTimeMillis() + " i ="+ thread.getI());
            //B段
            thread.suspend();
            Thread.sleep(5000);
            //C段
            thread.suspend();
            System.out.println("B = " + System.currentTimeMillis() + " i ="+ thread.getI());
            Thread.sleep(5000);
            System.out.println("B = " + System.currentTimeMillis() + " i ="+ thread.getI());
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

        stop()方法用户销毁线程对象,如果想继续运行线程,则必须使用start()重新启动线程,而suspend()方法用于让线程不再执行任务,线程对象并不销毁,只在当前所执行的代码处暂停,未来还可以恢复运行。

        从控制台输出的时间上来看,线程的确被暂停了,而且还可以恢复成运行状态。 

4.2 suspend()和resume()的缺点-独占

        如果suspend()和resume()方法使用不当,极易造成公共同步对象被独占,其他线程无法访问公共同步对象的结果。

【示例4.2】

public class SynchronzedObject {
    synchronized public void printString(){
        System.out.println("begin");
        if(Thread.currentThread().getName() .equals("a")){
            System.out.println("a 线程永远suspend");
            Thread.currentThread().suspend();
        }
        System.out.println("end");
    }
}
public class Run1 {
    public static void main(String[] args) {
        try {
            final  SynchronzedObject object = new SynchronzedObject();
            Thread t1 = new Thread(){
                @Override
                public void run(){
                    object.printString();

                }
            };
            t1.setName("a");
            t1.start();
            Thread.sleep(1000);

            Thread t2 = new Thread(){
                @Override
                public void run(){
                    System.out.println("t2启动了,但进入不了printString方法");
                    System.out.println("因为被t1锁定并永远suspend了");
                    object.printString();
                }
            };
            t2.start();

        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

4.3 使用LockSupport实现线程暂停与恢复

        suspend()和resume()方法时过期作废的,如果想实现同样的功能,可以使用JDK并发包里提供的LockSupport类作为替代,效果是一样的。

【示例4.3.1】 

public class MyThread1 extends Thread{
    @Override
    public void run(){
        System.out.println("begin" + System.currentTimeMillis()/1000);
        LockSupport.park();
        System.out.println("end" + System.currentTimeMillis()/1000);
    }
}
public class Run1 {
    public static void main(String[] args) throws InterruptedException {
        MyThread1 t1 = new MyThread1();
        t1.start();
        Thread.sleep(1000);
        LockSupport.unpark(t1);


    }
}

        park()方法的作用是将线程暂停,unpark()方法的作用是恢复线程的运行。如果先执行unpark在执行park方法,则park方法不会呈现暂停的效果。

4.4 yield()方法

        yield方法的作用是放弃当前的CPU资源,让其他任务去占用CPU执行时间,放弃的时间不确定,有可能刚刚放弃,马上有获取CPU时间片。

【4.4.1】

public class MyThread1 extends Thread{
    @Override
    public void run(){

        Long begin = System.currentTimeMillis() ;
        int count = 0;
        for (int i = 0; i < 5000000; i++) {
            //Thread.yield();
            count = count + (i + 1);

        }
        Long end = System.currentTimeMillis() ;
        System.out.println("用时:"+(end - begin) + "毫秒");
    }
}
public class Run1 {
    public static void main(String[] args) {
        MyThread1 t1 = new MyThread1();
        t1.start();
    }
}

第一次运行时,Thread.yield()方法注释,运行结果:

第二次运行时,Thread.yield()方法放开,运行结果:

第二次将CPU资源让给其他资源,导致速度变慢。

5 线程的优先级

        在操作系统中,线程可以划分优先级,优先级较高的线程得到的CPU资源较多,即CPU优先执行优先级较高的线程对象中的任务,其实就是让优先级高的线程获取更多的PCU时间片。

        设置线程优先级有助于“线程规划器”确定在下一次选择哪一个线程来优先执行。

        使用setPriority()方法设置线程的优先级,此方法在JDK的源码如下:

public final void setPriority(int newPriority) {
        ThreadGroup g;
        checkAccess();
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) != null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }

        在Java中线程的优先级分为10个等级,即1~10,如果小于1或大于10,则抛出

throw new IllegalArgumentException()。

        JDK使用三个常量来预定于优先级的值,代码如下:


    /**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;

5.1 线程优先级的继承特性

        在Java中,线程的优先级具有继承性,比如A线程启动B线程,则B线程的优先级与A是一样的。

【示例5.1.1】

public class MyThread2 extends Thread{
    @Override
    public void run(){
        System.out.println("MyThread2 的优先级 = " + this.getPriority());
    }
}
public class MyThread1 extends Thread{
    @Override
    public void run(){
        System.out.println("MyThread1 的优先级 = " + this.getPriority());
        MyThread2 t2 = new MyThread2();
        t2.start();
    }
}
public class Run1 {
    public static void main(String[] args) {
        System.out.println("开始时main线程的优先级 = " + Thread.currentThread().getPriority());
        //Thread.currentThread().setPriority(8);
        System.out.println("结束时main线程的优先级 = " + Thread.currentThread().getPriority());
        MyThread1 t1 = new MyThread1();
        t1.start();
    }
}

运行结果是

此时把Run1类的注释放开后,运行结果是

5.2 线程优先级的规律性

        虽然使用setPriority()方法可以设置线程的优先级,但还是没有看到设置优先级带来的效果。

【示例5.2.1】

public class MyThread3 extends Thread{
    @Override
    public void run(){
        long begin = System.currentTimeMillis();
        long addResult = 0L;
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 100000; j++) {
                Random random = new Random();
                random.nextInt();
                addResult = addResult + i;
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("t1 消耗时间 = " + (end - begin) + "毫秒");
    }

}
public class MyThread4 extends Thread{
    @Override
    public void run(){
        long begin = System.currentTimeMillis();
        long addResult = 0L;
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 100000; j++) {
                Random random = new Random();
                random.nextInt();
                addResult = addResult + i;
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("t2 消耗时间 = " + (end - begin) + "毫秒");
    }
}
public class Run2 {
    public static void main(String[] args) {

        for (int i = 0; i < 5; i++) {
            MyThread3 t1 = new MyThread3();
            t1.setPriority(1);
            t1.start();
            MyThread4 t2 = new MyThread4();
            t2.setPriority(10);
            t2.start();

        }

    }
}

        高优先级的线程总是大部分先执行王城,但不代表高优先级的线程全部执行完成。另外,并不是t1线程先被main线程调用就先执行完。当线程优先级的等级差距很大时,谁先执行完和代码的调用顺序无关。

5.3 守护线程

        Java中有两种线程,一种是用户线程(非守护线程),另一种是守护线程。

        守护线程是一种特殊的线程,当进程中不存在非守护时,则守护线程自动销毁。典型的守护线程就是垃圾回收线程,当进程中没有非守护线程,则垃圾会后线程也没有存在的必要,会自动销毁。主线程main在本篇中属于用户线程,凡是调用setDaemon(true)方法并且参数为true时的线程才是守护线程。

【示例5.3.1】

public class MyThread extends Thread{
    private  int i = 0;
    @Override
    public void run(){
        try {
           while (true){
               i ++;
               System.out.println("i = " + i);
               Thread.sleep(1000);
           }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
public class Run1 {
    public static void main(String[] args) {
        try {
            MyThread t1 = new MyThread();
            t1.setDaemon(true);
            t1.start();
            Thread.sleep(5000);
            System.out.println("我离开了t1对象也不再打印了吗,就是停止了");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

【注意】要在执行start方法前先执行setDaemon(boolean)方法,不然会出现异常。 

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

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

相关文章

Docker中的RabbitMQ已经启动运行,但是管理界面打不开

文章目录 前言一、解决方法方法一方法二 总结 前言 肯定有好多小伙伴在学习RabbitMQ的过程中&#xff0c;发现镜像运行&#xff0c;但是我的管理界面怎么进不去&#xff0c;或者说我第一天可以进去&#xff0c;怎么第二天进不去了&#xff0c;为什么每次重新打开虚拟机都进不去…

Linux 基本语句_11_无名管道文件复制

父子进程&#xff1a; 父子进程的变量之间存在着读时共享&#xff0c;写时复制原则 无名管道&#xff1a; 无名管道仅能用于有亲缘关系的进程之间通信如父子进程 代码&#xff1a; #include <stdio.h> #include <unistd.h> #include <sys/types.h> #inc…

IDEA 搭建 SpringCloud 项目【超详细步骤】

文章目录 一、前言二、项目搭建1. 数据库准备2. 创建父工程3. 创建注册中心4. 服务注册5. 编写业务代码6. 服务拉取 一、前言 所谓微服务&#xff0c;就是要把整个业务模块拆分成多个各司其职的小模块&#xff0c;做到单一职责原则&#xff0c;不会重复开发相同的业务代码&…

HC-SR501传感器制作一个报警系统

接线图&#xff1a; 引脚连接&#xff1a; 1. 将 PIR 信号引脚连接到 arduino 数字 引脚 13。 2. 将 PIR V 引脚连接 到 arduino 5v 引脚。 3. 将 PIR GND 引脚连接到 arduino GND 引脚。 4. 将arduino数字 引脚12连接 到220欧姆电阻&#xff0c;并将该电阻连接到 LED V …

用户增长模型:3A3R策略模型

一、概述 A - A - A - R - R - R 增长模型&#xff0c;即3A3R策略模型&#xff0c;由海盗模型演变而来&#xff0c;是目前使用最多、适用范围最广的增长策略模型。原始的海盗模型由 Acquisition &#xff08;获客&#xff09;、 Activation &#xff08;活跃&#xff09;、 Re…

mfc140.dll是什么文件?如何修复mfc140.dll丢失的方法分享

​mfc140.dll丢失的原因 未正确安装Microsoft Visual C Redistributable&#xff1a;mfc140.dll是Visual C库的一部分&#xff0c;如果没有正确安装Visual C Redistributable&#xff0c;可能导致mfc140.dll丢失。 系统文件损坏&#xff1a;由于病毒感染、系统错误或其他原因…

Java面向对象(高级)-- 单例(Singleton)设计模式

文章目录 一、单例设计模式&#xff08;1&#xff09; 设计模式概述&#xff08;2&#xff09; 何为单例模式&#xff08;3&#xff09; 实现思路&#xff08;4&#xff09; 单例模式的两种实现方式1. 饿汉式2. 懒汉式3. 饿汉式 vs 懒汉式 &#xff08;5&#xff09; 单例模式的…

SQL零基础入门教程,贼拉详细!贼拉简单! 速通数据库期末考!(九)

UNION ALL UNION ALL 用于合并两个或多个 SELECT 语句的结果。 请注意&#xff0c;UNION ALL 合并的每个 SELECT 语句必须是查询相同数量&#xff0c;相同数据类型的字段&#xff0c;且顺序也必须一致。另外结果集中的列名总是等于 UNION ALL 中第一个 SELECT 语句中的列名。 …

PyQt(学习笔记)

学习资料来源&#xff1a; PyQt快速入门——b站王铭东老师 PyQt&#xff08;学习笔记&#xff09; Pycharm环境准备运行第一个程序QPushButtonQLabelQLineEdit调整窗口大小、位置、图标布局信号与槽PyQt引入多线程 Pycharm环境准备 新建环境——添加PyQt5模块——验证版本 如果…

视频封面:从视频中提取封面,轻松制作吸引人的视频

在当今的数字时代&#xff0c;视频已成为人们获取信息、娱乐和交流的重要方式。一个吸引人的视频封面往往能抓住眼球&#xff0c;提高点击率和观看率。今天将介绍如何从视频中提取封面&#xff0c;轻松制作吸引人的视频封面。 一、准备素材选择合适的视频片段 首先&#xff0…

光敏传感器模块(YH-LDR)

目录 1. YH-LDR模块说明 1.1 简介 1.2 YH-LDR 模块的引脚说明 1.3 LDR 传感器工作原理与输出特性 2. 使用单片机系统控制 YH-LDR 模块 2.1 通用控制说明 1. YH-LDR模块说明 1.1 简介 YH-LDR 是野火设计的光强传感器&#xff0c;使用一个光敏电阻作为采集源&#x…

设计模式(二)-创建者模式(2)-工厂模式

一、为何需要工厂模式&#xff08;Factory Pattern&#xff09;? 由于简单工厂模式存在一个缺点&#xff0c;如果工厂类创建的对象过多&#xff0c;使得代码变得越来越臃肿。这样导致工厂类难以扩展新实例&#xff0c;以及难以维护代码逻辑。于是在简单工厂模式的基础上&…

SPASS-距离分析

基本概念 距离分析是对观测量之间相似或不相似程度的一种测度&#xff0c;是计算一对观测量之间的广义距离。这些相似性或距离测度可以用于其他分析过程&#xff0c;例如因子分析、聚类分析或多维定标分析&#xff0c;有助于分析复杂的数据集。 统计原理 不相似性测度 对定距…

STM32F4系列单片机GPIO概述和寄存器分析

第2章 STM32-GPIO口 2.1 GPIO口概述 通用输入/输出口 2.1.1 GPIO口作用 GPIO是单片机与外界进行数据交流的窗口。 2.1.2 STM32的GPIO口 在51单片机中&#xff0c;IO口&#xff0c;以数字进行分组&#xff08;P0~P3&#xff09;&#xff0c;每一组里面又有8个IO口。 在ST…

月子会所信息展示服务预约小程序的作用是什么

传统线下门店经营只依赖自然流量咨询或简单的线上付费推广是比较低效的&#xff0c;属于靠“天”吃饭&#xff0c;如今的年轻人学历水平相对较高&#xff0c;接触的事物或接受的思想也更多更广&#xff0c;加之生活水平提升及互联网带来的长期知识赋能&#xff0c;因此在寻找/咨…

【刷题专栏—突破思维】LeetCode 142. 环形链表 II

前言&#xff1a;本篇博客将讲解三个OJ题&#xff0c;前两个作为铺垫&#xff0c;最后完成环形链表的节点的寻找 文章目录 一、160. 相交链表二、141. 环形链表三、142. 环形链表II 一、160. 相交链表 题目链接&#xff1a;LeetCode—相交链表 题目描述&#xff1a; 给你两个单…

【心得】PHP的文件上传个人笔记

目录 1 php的文件上传绕过 黑名单绕过 2 php文件上传的00截断 3 iconv字符转换异常后造成了字符截断 4 文件后缀是白名单的时候的绕过 web服务器的解析漏洞绕过 5.高级文件上传绕过 1 .htaccess nginx.htaccess 2 服务端内容检测 3 配合伪协议来绕过 4.配合日志包含绕…

2023年【安全员-B证】考试内容及安全员-B证考试资料

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 安全员-B证考试内容参考答案及安全员-B证考试试题解析是安全生产模拟考试一点通题库老师及安全员-B证操作证已考过的学员汇总&#xff0c;相对有效帮助安全员-B证考试资料学员顺利通过考试。 1、【多选题】《中华人民…

FL Studio2024免费编曲音乐制作软件

用FL Studio编曲&#xff0c;让音乐成为你的翅膀&#xff0c;飞翔在无尽的创作海洋中吧&#xff01; FL Studio作为一款功能强大且备受赞誉的音乐制作软件&#xff0c;为你提供了一个独特的创作平台。通过FL Studio&#xff0c;你可以自由地创作、编曲&#xff0c;制作属于自己…

【算法萌新闯力扣】:旋转字符串

力扣热题&#xff1a;796.旋转字符串 开篇 今天下午刷了6道力扣算法题&#xff0c;选了一道有多种解法的题目与大家分享。 题目链接:796.旋转字符串 题目描述 代码思路 完全按照题目的要求&#xff0c;利用StringBuffer中的方法对字符串进行旋转&#xff0c;寻找相同的一项 …