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.mzph.cn/news/148217.shtml

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

相关文章

asp.net mvc点餐系统餐厅管理系统

1. 主要功能 ① 管理员、收银员、厨师的登录 ② 管理员查看、添加、删除菜品类型 ③ 管理员查看、添加、删除菜品&#xff0c;对菜品信息进行简介和封面的修改 ④ 收银员浏览、搜索菜品&#xff0c;加入购物车后进行结算&#xff0c;生成订单 ⑤ 厨师查看待完成菜品信息…

开拓经验专栏:从十来天的晨型人体验开始

文章目录 拓新缘起契机实践心得 拓新 确定要新开一个板块&#xff0c;用来记录持续自我提升的经验和教训&#xff0c;着实遭遇了不少阻力。 首先&#xff0c;我的语文功底一向不行&#xff0c;当年高考前&#xff0c;语文分数在及格线上下跳动都是常事&#xff0c;现在却要通…

DAC实验(DAC 输出三角波实验)(DAC 输出正弦波实验)

DAC 输出三角波实验 本实验我们来学习使用如何让 DAC 输出三角波&#xff0c;DAC 初始化部分还是用 DAC 输出实验 的&#xff0c;所以做本实验的前提是先学习 DAC 输出实验。 使用 DAC 输出三角波&#xff0c;通过 KEY0/KEY1 两个按键&#xff0c;控制 DAC1 的通道 1 输出两种…

LinkWeChat V4.9.8 版本发布

LinkWeChat v4.9.8 已经发布&#xff0c;基于企业微信的 SCRM 系统 LinkWeChat 是国内首个基于企业微信的开源 SCRM&#xff0c;在集成了企微强大的开放能力的基础上&#xff0c;进一步升级拓展灵活高效的客户运营能力及多元化精准营销能力&#xff0c;让客户与企业之间建立强…

Nginx反向代理和负载均衡

1.反向代理 反向代理&#xff08;Reverse Proxy&#xff09;方式是指以代理服务器来接受internet上的连接请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff0c;并将从服务器上得到的结果返回给internet上请求连接的客户端&#xff0c;此时代理服务器对外就表现为一…

记录:RK3568显示异常。

最近调一个RK3568的新板子&#xff0c;板子其它接口功能都调试ok。可唯独在适配显示时发现&#xff0c;HDMI和MIPI显示均出现异常。当系统启动要进入桌面时候内核就开始报错。 因为这套源码之前在其它的板子上适配过&#xff0c;所以第一反应就是硬件问题或者是那个电压没配置…

SQL注入1

对sql进行一个小结 还有其他的注入 其他注入:堆叠注入&#xff0c;宽字节注入&#xff0c;二次注入 首先是数值和字符 id1 and 11和id1 and 12 如果这两个语句返回的页面不一样就说明是数字型 id1 and 11#和id1 and 12# 如果这两个语句返回的页面不一样就说明是字符型 常…

【Promise12数据集】Promise12数据集介绍和预处理

【Segment Anything Model】做分割的专栏链接&#xff0c;欢迎来学习。 【博主微信】cvxiayixiao 本专栏为公开数据集的介绍和预处理&#xff0c;持续更新中。 要是只想把Promise12数据集的raw形式分割为png形式&#xff0c;快速导航&#xff0c;直接看2&#xff0c;4标题即可 …

【精选】项目管理工具——Maven详解

Maven简介 Maven是一个项目管理工具。它可以帮助程序员构建工程&#xff0c;管理jar包&#xff0c;编译代码&#xff0c;完成测试&#xff0c;项目打包等等。 Maven工具是基于POM&#xff08;Project Object Model&#xff0c;项目对象模型&#xff09;实现的。在Maven的管理下…

Spring Framework 6.1 正式 GA

Spring Framework 6.1在运行时方面针对 JDK 21 和 Jakarta EE 10 上提供了一级支持&#xff0c;同时保留了 JDK 17 和 Jakarta EE 9 基线。Spring 还通过精细的元数据推理跟踪 GraalVM for JDK 21 的演变&#xff0c;同时暂时保持与 GraalVM 22.3 的兼容性。 主要变化 支持 JD…

Unity在Windows选项下没有Auto Streaming

Unity在Windows选项下没有Auto Streaming Unity Auto Streaming插件按网上说的不太好使最终解决方案 Unity Auto Streaming插件 我用的版本是个人版免费版&#xff0c;版本号是&#xff1a;2021.2.5f1c1&#xff0c;我的里边Windows下看不到Auto Streaming选项,就像下边这张图…

Python-pptx教程之二操作已有PPT模板文件

文章目录 简单的案例找到要修改的元素修改幻灯片中的文本代码使用示例 修改幻灯片的图片代码使用示例 删除幻灯片代码使用示例 获取PPT中所有的文本内容获取PPT中所有的图片总结 在上一篇中我们已经学会了如何从零开始生成PPT文件&#xff0c;从零开始生成较为复杂的PPT是非常消…

Jmeter——循环控制器中实现Counter计数器的次数重置

近期在使用Jmeter编写个辅助测试的脚本&#xff0c;用到了多个Loop Controller和Counter。 当时想的思路就是三个可变的数量值&#xff0c;使用循环实现&#xff1b;但第三个可变值的数量次数&#xff0c;是基于第二次循环中得到的结果才能确认最终次数&#xff0c;每次的结果…

爱奇艺大数据离在线混部

混部作为一种提高资源利用率、降低成本的的方案&#xff0c;被业界普遍认可。爱奇艺在云原生化与降本增效的过程中&#xff0c;成功将大数据离线计算、音视频内容处理等工作负载与在线业务进行了混部&#xff0c;并且取得了阶段性收益。本文重点以大数据为例&#xff0c;介绍从…

HDFS、MapReduce原理--学习笔记

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

多线程(初阶)

文章目录 一、认识线程&#xff08;Thread&#xff09;1.1 概念1.1.1 什么是线程1.1.2 为什么要有线程1.1.3 进程和线程的区别&#xff08;重要&#xff09;1.1.4 Java的线程和操作系统线程的关系 1.2 第一个多线程 程序1.3 创建线程&#xff08;重要&#xff09;1.3.1 继承 Tr…

iframe渲染后端接口文件和实现下载功能

一&#xff1a;什么是iframe&#xff1f; 1、介绍 iframe 是HTML 中的一种标签&#xff0c;全称为 Inline Frame&#xff0c;即内联框架。它可以在网页中嵌入其他页面或文档&#xff0c;将其他页面的内容以框架的形式展示在当前页面中。iframe的使用方式是通过在HTML文档中插入…

Linux_安装docker

安装包管理工具yum-utils&#xff0c;并设置docker储存库&#xff08;如果已有&#xff0c;不用安装&#xff09; # 安装包管理工具 sudo yum install -y yum-utils # 安装docker储存库 sudo yum-config-manager \--add-repo \http://mirrors.aliyun.com/docker-ce/linux/cen…

react之基于@reduxjs/toolkit使用react-redux

react之基于reduxjs/toolkit使用react-redux 一、配置基础环境二、使用React Toolkit 创建 counterStore三、为React注入store四、React组件使用store中的数据五、实现效果六、提交action传递参数七、异步状态操作 一、配置基础环境 1.使用cra快速创建一个react项目 npx crea…

python图

有向图&#xff1a;图中的每条边都有方向的图叫有向图。此时&#xff0c;边的两个顶点有次序关系&#xff0c;有向边 < u,v>成为从顶点u到顶点v的一条弧&#xff0c;u成为弧尾&#xff08;始点&#xff09;&#xff0c;v成为弧头&#xff08;终点&#xff09;&#xff0c…