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

接上篇: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{@Overridepublic 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{@Overridepublic 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{@Overridepublic 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{@Overridepublic 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;}@Overridepublic 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(){@Overridepublic void run(){object.printString();}};t1.setName("a");t1.start();Thread.sleep(1000);Thread t2 = new Thread(){@Overridepublic 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{@Overridepublic 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{@Overridepublic 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{@Overridepublic void run(){System.out.println("MyThread2 的优先级 = " + this.getPriority());}
}
public class MyThread1 extends Thread{@Overridepublic 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{@Overridepublic 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{@Overridepublic 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;@Overridepublic 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.rhkb.cn/news/197639.html

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

相关文章

docker-compose 部署 MySQL 8

目录 前言MySQL 配置文件(my.cnf)docker-compose.yml安装卸载 前言 Windows/Linux 系统通过 docker-compose 部署 MySQL8.0。 MySQL 配置文件(my.cnf) # 服务端参数配置 [mysqld] usermysql # MySQL启动用户 default-storage-engineINNODB # 创建新表时…

【脑与认知科学】【n-back游戏】

请参考课堂内容&#xff0c;设计一种测试工作记忆的实验方法&#xff0c;并选择三位同学作为被试测试工作记忆。请画出实验流程图&#xff0c;叙述实验测试目标&#xff0c;并分析实验结果。 举例&#xff1a;一般我们选择n_back来测试对数字或字母的记忆&#xff0c;选择色块实…

springboot实现在线人数统计

在线人数统计 笔者做了一个网站&#xff0c;需要统计在线人数。 在线有两种&#xff1a; 一、如果是后台系统如果登录算在线&#xff0c;退出的时候或者cookie、token失效的时候就算下线 二、如果是网站前台&#xff0c;访问的时候就算在线 今天我们来讲一下第2种情况&…

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

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

数据结构与算法-图

图 &#x1f388;2.图的存储结构&#x1f4d6;2.4.2邻接表的存储✅2.4.2.1逆邻接表✅2.4.2.2邻接表存储结构的定义✅2.4.2.3邻接表存储结构的类定义✅2.4.2.4创建n个顶点m条边的无向网✅2.4.2.5创建n个顶点m条边的有向网✅2.4.2.6定位操作-查找定点信息在顶点数组中的下标✅2.4…

3GPP协议解读(一)_23.501_23.502_PDU Session_SMF与UDP的交互

UE发起计算服务申请后&#xff0c;网络侧处理的流程 UE发起服务的流程&#xff1a;service request网络侧处理服务涉及的通信数据通过PDU Session进行传输&#xff0c;涉及到SMF与UPF的交互。PDU Session的建立、管理全部由SMF&#xff08;Session Management Function&#x…

【uniapp】 video视频层级、遮挡其他弹窗或顶部导航 使用nvue覆盖

uniapp 顶部导航和弹窗被video遮挡解决办法 第一步&#xff1a;配置 subNVues {"path": "pages/index/index","style": {"navigationBarTitleText": "uni-app","navigationStyle": "custom","app-…

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

FULL OUTER JOIN 除了前面讲到的 INNER JOIN&#xff08;内连接&#xff09;、LEFT JOIN&#xff08;左连接&#xff09;、RIGHT JOIN&#xff08;右连接&#xff09;&#xff0c;还有另外一种关联方式&#xff0c;即 FULL OUTER JOIN&#xff08;全外连接&#xff09; FULL O…

Javaweb之Vue指令案例的详细解析

2.3.5 案例 需求&#xff1a; 如上图所示&#xff0c;我们提供好了数据模型&#xff0c;users是数组集合&#xff0c;提供了多个用户信息。然后我们需要将数据以表格的形式&#xff0c;展示到页面上&#xff0c;其中&#xff0c;性别需要转换成中文男女&#xff0c;等级需要…

java游戏制作-拼图游戏

一.制作主界面 首先创建一个Java项目命名为puzzlegame。 再在src中创建一个包&#xff0c;用来制作主界面 代码&#xff1a; 结果&#xff1a; 二.设置界面 代码&#xff1a; 三.初始化界面 代码&#xff1a; 优化代码&#xff1a; 结果&#xff1a; 四.添加图片 先在Java项…

HDFS、MapReduce原理--学习笔记

1.Hadoop框架 1.1框架与Hadoop架构简介 &#xff08;1&#xff09;广义解释 从广义上来说&#xff0c;随着大数据开发技术的快速发展与逐步成熟&#xff0c;在行业里&#xff0c;Hadoop可以泛指为&#xff1a;Hadoop生态圈。 也就是说&#xff0c;Hadoop指的是大数据生态圈整…

机器学习的医疗乳腺癌数据的乳腺癌疾病预测

项目视频讲解:基于机器学习的医疗乳腺癌数据的乳腺癌疾病预测 完整代码数据分享_哔哩哔哩_bilibili 效果演示: 代码: #第一步!导入我们需要的工具 import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns %matplotlib inlin…

Postman实现接口的加密和解密

近期在复习Postman的基础知识&#xff0c;在小破站上跟着百里老师系统复习了一遍&#xff0c;也做了一些笔记&#xff0c;希望可以给大家一点点启发。 1、目前市面上的加密的方式 对称式加密&#xff1a;DES&#xff0c;AES&#xff0c;Base64加密算法 非对称加密&#xff1a…

跟随鼠标的粒子特效分享

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 广告打完,我们进入正题,先看效果: 上代码: html, body {padding: 0;margin: 0;overflow: hidden; }import * as PIXI from https://cdn.skypack.dev/pixi.js@7.2.…

若依启动步骤

1.创建数据库 2.启动redis 3.改后端的数据库连接配置 4.配置redis redis的地址&#xff1a;cmd中ipconfig命令查看 6.启动后端&#xff1a;如下 7.启动前端ruoyi-ui中 先运行npm install&#xff0c;再npm run dev。项目就启动成功了。 用户名&#xff1a;admin 密码&#x…

C#入门(1):程序结构、数据类型

一、C#程序结构 第一个C#程序 using System;namespace base_01 {class Program{#region 代码折叠块static void Main(string[] args){//控制台输出Console.WriteLine("Hello World!");Console.Write("C#是微软的编程语言"); //不换行输出//Console.Rea…

蓝桥杯 map

map 代码示例 #include<iostream> #include<map> using namespace std; int main(){//创建并初始化mapmap<int,string> myMap{{1,"Apple"},{2,"Banana"},{3,"Orange"}} ;//插入元素myMap.insert(make_pair(4,"Grapes&qu…

神经网络常见评价指标AUROC(AUC-ROC)、AUPR(AUC-PR)

神经网络的性能可以通过多个评价指标进行衡量&#xff0c;具体选择哪些指标取决于任务的性质。以下是神经网络中常见的评价指标&#xff1a; 准确性&#xff08;Accuracy&#xff09;&#xff1a; 准确性是最常见的分类任务评价指标&#xff0c;表示模型正确预测的样本数占总样…

资深测试总结,现在软件测试有未来吗?“你“的底气在哪里?

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、为什么会有 “…

3DMAX森林树木植物插件ForestPackLite教程

3DMAX森林树木植物插件ForestPackLite教程 Forest Pack是世界上最受欢迎的散布插件。它提供了一个完整的解决方案来创建大面积的物体&#xff0c;从树木和植物到建筑、人群、骨料、地面覆盖物、岩石等等。如果你能为它建模&#xff0c;森林包就能把它分散开来。 无数工作室依靠…