Java总结篇系列:Java多线程(二)
本文承接上一篇文章《Java总结篇系列:Java多线程(一)》。
四.Java多线程的阻塞状态与线程控制
上文已经提到Java阻塞的几种具体类型。下面分别看下引起Java线程阻塞的主要方法。
1.join()
join —— 让一个线程等待另一个线程完成才继续执行。如A线程线程执行体中调用B线程的join()方法,则A线程被阻塞,知道B线程执行完为止,A才能得以继续执行。
1 public class ThreadTest { 2 3 public static void main(String[] args) { 4 5 MyRunnable myRunnable = new MyRunnable(); 6 Thread thread = new Thread(myRunnable); 7 8 for (int i = 0; i < 100; i++) { 9 System.out.println(Thread.currentThread().getName() + " " + i); 10 if (i == 30) { 11 thread.start(); 12 try { 13 thread.join(); // main线程需要等待thread线程执行完后才能继续执行 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 } 18 } 19 } 20 } 21 22 class MyRunnable implements Runnable { 23 24 @Override 25 public void run() { 26 for (int i = 0; i < 100; i++) { 27 System.out.println(Thread.currentThread().getName() + " " + i); 28 } 29 } 30 }
2.sleep()
sleep —— 让当前的正在执行的线程暂停指定的时间,并进入阻塞状态。在其睡眠的时间段内,该线程由于不是处于就绪状态,因此不会得到执行的机会。即使此时系统中没有任何其他可执行的线程,出于sleep()中的线程也不会执行。因此sleep()方法常用来暂停线程执行。
前面有讲到,当调用了新建的线程的start()方法后,线程进入到就绪状态,可能会在接下来的某个时间获取CPU时间片得以执行,如果希望这个新线程必然性的立即执行,直接调用原来线程的sleep(1)即可。
1 public class ThreadTest { 2 3 public static void main(String[] args) { 4 5 MyRunnable myRunnable = new MyRunnable(); 6 Thread thread = new Thread(myRunnable); 7 8 for (int i = 0; i < 100; i++) { 9 System.out.println(Thread.currentThread().getName() + " " + i); 10 if (i == 30) { 11 thread.start(); 12 try { 13 Thread.sleep(1); // 使得thread必然能够马上得以执行 14 } catch (InterruptedException e) { 15 e.printStackTrace(); 16 } 17 } 18 } 19 } 20 } 21 22 class MyRunnable implements Runnable { 23 24 @Override 25 public void run() { 26 for (int i = 0; i < 100; i++) { 27 System.out.println(Thread.currentThread().getName() + " " + i); 28 } 29 } 30 }
注:睡一个毫秒级够了,因为CPU不会空闲,会切换到新建的线程。
3.后台线程(Daemon Thread)
概念/目的:后台线程主要是为其他线程(相对可以称之为前台线程)提供服务,或“守护线程”。如JVM中的垃圾回收线程。
生命周期:后台线程的生命周期与前台线程生命周期有一定关联。主要体现在:当所有的前台线程都进入死亡状态时,后台线程会自动死亡(其实这个也很好理解,因为后台线程存在的目的在于为前台线程服务的,既然所有的前台线程都死亡了,那它自己还留着有什么用...伟大啊 ! !)。
设置后台线程:调用Thread对象的setDaemon(true)方法可以将指定的线程设置为后台线程。
1 public class ThreadTest { 2 3 public static void main(String[] args) { 4 Thread myThread = new MyThread(); 5 for (int i = 0; i < 100; i++) { 6 System.out.println("main thread i = " + i); 7 if (i == 20) { 8 myThread.setDaemon(true); 9 myThread.start(); 10 } 11 } 12 } 13 14 } 15 16 class MyThread extends Thread { 17 18 public void run() { 19 for (int i = 0; i < 100; i++) { 20 System.out.println("i = " + i); 21 try { 22 Thread.sleep(1); 23 } catch (InterruptedException e) { 24 // TODO Auto-generated catch block 25 e.printStackTrace(); 26 } 27 } 28 } 29 }
判断线程是否是后台线程:调用thread对象的isDeamon()方法。
注:main线程默认是前台线程,前台线程创建中创建的子线程默认是前台线程,后台线程中创建的线程默认是后台线程。调用setDeamon(true)方法将前台线程设置为后台线程时,需要在start()方法调用之前。前天线程都死亡后,JVM通知后台线程死亡,但从接收指令到作出响应,需要一定的时间。
4.改变线程的优先级/setPriority():
每个线程在执行时都具有一定的优先级,优先级高的线程具有较多的执行机会。每个线程默认的优先级都与创建它的线程的优先级相同。main线程默认具有普通优先级。
设置线程优先级:setPriority(int priorityLevel)。参数priorityLevel范围在1-10之间,常用的有如下三个静态常量值:
MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5
获取线程优先级:getPriority()。
注:具有较高线程优先级的线程对象仅表示此线程具有较多的执行机会,而非优先执行。
1 public class ThreadTest { 2 3 public static void main(String[] args) { 4 Thread myThread = new MyThread(); 5 for (int i = 0; i < 100; i++) { 6 System.out.println("main thread i = " + i); 7 if (i == 20) { 8 myThread.setPriority(Thread.MAX_PRIORITY); 9 myThread.start(); 10 } 11 } 12 } 13 14 } 15 16 class MyThread extends Thread { 17 18 public void run() { 19 for (int i = 0; i < 100; i++) { 20 System.out.println("i = " + i); 21 } 22 } 23 }
5.线程让步:yield()
上一篇博文中已经讲到了yield()的基本作用,同时,yield()方法还与线程优先级有关,当某个线程调用yiled()方法从运行状态转换到就绪状态后,CPU从就绪状态线程队列中只会选择与该线程优先级相同或优先级更高的线程去执行。
1 public class ThreadTest { 2 3 public static void main(String[] args) { 4 Thread myThread1 = new MyThread1(); 5 Thread myThread2 = new MyThread2(); 6 myThread1.setPriority(Thread.MAX_PRIORITY); 7 myThread2.setPriority(Thread.MIN_PRIORITY); 8 for (int i = 0; i < 100; i++) { 9 System.out.println("main thread i = " + i); 10 if (i == 20) { 11 myThread1.start(); 12 myThread2.start(); 13 Thread.yield(); 14 } 15 } 16 } 17 18 } 19 20 class MyThread1 extends Thread { 21 22 public void run() { 23 for (int i = 0; i < 100; i++) { 24 System.out.println("myThread 1 -- i = " + i); 25 } 26 } 27 } 28 29 class MyThread2 extends Thread { 30 31 public void run() { 32 for (int i = 0; i < 100; i++) { 33 System.out.println("myThread 2 -- i = " + i); 34 } 35 } 36 }
Java总结篇系列:Java多线程(二)相关推荐
- Java总结篇系列:Java多线程(三)
2019独角兽企业重金招聘Python工程师标准>>> 本文主要接着前面多线程的两篇文章总结Java多线程中的线程安全问题. 一.一个典型的Java线程安全例子 public cla ...
- Java高级篇——深入浅出Java类加载机制
转载自 Java高级篇--深入浅出Java类加载机制 类加载器 简单讲,类加载器ClassLoader的功能就是负责将class文件加载到jvm内存. 类加载器分类 从虚拟机层面讲分为两大类型的类加载 ...
- Java核心篇之Java锁--day2
Java核心篇之Java锁–day2 乐观锁:乐观锁是一种乐观思想,即认为读多写少,每次去取数据的时候都认为其他人不会修改,所以不会上锁:但是在更新的时候会判断一下在此期间别人有没有去修改它,如果有人 ...
- 跳槽者、应届生必看JAVA面试题系列 - JAVA基础知识(四)
一: 前言 莫等闲,白了少年头,空悲切. 二: 面试挑战 在文章开始前,首先安利下"面试挑战": 凡是满足下面的挑战条件的,如果一个月内没有拿到一个Offer的,免费提供简历封 ...
- JAVA高级篇之Java Reflection详解
目录 概念 Java programming language and JVM modeling in core reflection 场景 Class加载 ClassLoad加载 Class加载 通 ...
- Java总结篇系列:Java多线程(一)
多线程作为Java中很重要的一个知识点,在此还是有必要总结一下的. 一.线程的生命周期及五种基本状态 关于Java中线程的生命周期,首先看一下下面这张较为经典的图: 上图中基本上囊括了Java中多线程 ...
- Java总结篇系列:Java泛型
一. 泛型概念的提出(为什么需要泛型)? 首先,我们看下下面这段简短的代码: 1 public class GenericTest {2 3 public static void main(Strin ...
- Java并发编程系列18:多线程之生产者和消费者模式_信号灯法(wait/notify通知机制)
1.生产者消费者模式 生产者消费者问题(Producer-consumer problem),也称为有限缓冲问题(Bounded-buffer problem),是一个多线程同步问题的经典案例.该问题 ...
- 【java学习之路】(java SE篇)010.多线程
多线程 线程的概念 程序 是一个指令的集合 进程 (正在执行中的程序)是一个静态的概念 进程是程序的一次静态执行过程,占用特定的地址空间 每个进程都是独立的,由三部分组成 cpu data code ...
最新文章
- PMCAFF | 别学东学西了,先建立自己的知识体系吧
- node+express项目链接MySQL数据库(最简单版)
- oracle 12c sp2 0667,SP2-0667/SP2-0750错误
- 视频隐身衣:物体移除、去水印、后期处理毫无痕迹
- 玩转SpringBoot 2.x 解析BeanPostProcessor原理篇
- ios高效开发-正确的使用枚举(Enum)
- 你必须掌握的Python数据分析工具之Pandas
- 求职者:推销自己的四大妙招
- 晒下自己App广告平台积分墙收入,顺便点评几个广告平台
- 『原创』老范的来电防火墙v1.0发布了(图文)
- matlab使用矩形窗设计一个具有线性相位的低通数字滤波器,matlab结合矩形窗设计fir滤波器.doc...
- ArcGIS API for JavaScript开发之必学渲染方式及渲染符号概念(0)
- windows server backup功能
- 《网络攻防第二周作业》
- 批量实现json_to_dataset将json文件转换为训练所需的dataset
- 衣服裤子染色了怎么办
- 100个小学生猜字谜大全及答案
- C#获取本机上所有网络接口及真实IP地址信息
- 【FFmpeg】avg_frame_rate 计算 及在TS 中使用
- navicat8.0版本注册码,已试可用