多线程 java 实例_Java多线程实例学习
1. Java多线程的就绪、运行和死亡状态
就绪状态转换为运行状态:当此线程得到处理器资源;
运行状态转换为就绪状态:当此线程主动调用yield()方法或在运行过程中失去处理器资源。
运行状态转换为死亡状态:当此线程线程执行体执行完毕或发生了异常。
此处需要特别注意的是:当调用线程的yield()方法时,线程从运行状态转换为就绪状态,但接下来CPU调度就绪状态中的哪个线程具有一定的随机性,因此,可能会出现A线程调用了
yield()方法后,接下来CPU仍然调度了A线程的情况。
由于实际的业务需要,常常会遇到需要在特定时机终止某一线程的运行,使其进入到死亡状态。目前最通用的做法是设置一boolean型的变量,当条件满足时,使线程执行体快速执行完毕。如:
1. 代码
package test;
public class TestStopThread {
public static void main(String[] args) {
MyThread myThread = new MyThread("MyThread");
Thread thread = new Thread(myThread);
for(int i=0; i<100; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(i == 10){
thread.start();
}
if(i == 30){
myThread.stopThread();
}
}
}
}
class MyThread implements Runnable{
boolean stop = false;
private int i = 50;
private String threadName;
public MyThread(String threadName){
this.threadName = threadName;
}
@Override
public void run() {
while (!stop && i>0){
System.out.println(threadName + "-->" + i--);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void stopThread(){
stop = true;
}
}
2. 运行结果:
main-->0
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9
main-->10
main-->11
MyThread-->50
MyThread-->49
main-->12
MyThread-->48
main-->13
MyThread-->47
main-->14
main-->15
MyThread-->46
main-->16
MyThread-->45
MyThread-->44
main-->17
MyThread-->43
main-->18
MyThread-->42
main-->19
MyThread-->41
main-->20
main-->21
MyThread-->40
main-->22
MyThread-->39
MyThread-->38
main-->23
main-->24
MyThread-->37
MyThread-->36
main-->25
main-->26
MyThread-->35
main-->27
MyThread-->34
main-->28
MyThread-->33
MyThread-->32
main-->29
main-->30
MyThread-->31
MyThread-->30
main-->31
main-->32
main-->33
main-->34
main-->35
...
2. Java多线程的阻塞状态与线程控制
1. join()
让一个线程等待另一个线程完成才继续执行。如A线程线程执行体中调用B线程的join()方法,则A线程被阻塞,知道B线程执行完为止,A才能得以继续执行。
(1)代码实例:
package test;
public class TestJoin {
public static void main(String[] args) {
MyJoin myJoin = new MyJoin();
Thread thread = new Thread(myJoin, "MyJoin");
for(int i=0; i<30; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
if(i == 10){
thread.start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(i == 20){
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class MyJoin implements Runnable{
@Override
public void run() {
for(int i=0; i<20; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
(2)运行结果:
main-->0
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9
main-->10
MyJoin-->0
MyJoin-->1
MyJoin-->2
MyJoin-->3
MyJoin-->4
MyJoin-->5
MyJoin-->6
MyJoin-->7
MyJoin-->8
MyJoin-->9
MyJoin-->10
MyJoin-->11
MyJoin-->12
MyJoin-->13
MyJoin-->14
MyJoin-->15
MyJoin-->16
MyJoin-->17
MyJoin-->18
MyJoin-->19
main-->11
main-->12
main-->13
main-->14
main-->15
main-->16
main-->17
main-->18
main-->19
main-->20
main-->21
main-->22
main-->23
main-->24
main-->25
main-->26
main-->27
main-->28
main-->29
可以看到,当main线程中join 了MyJoin线程后,会暂停main线程,直到MyJoin线程执行完毕再执行main,这就是join方法,说简单点,就是A线程中调用B线程join方法,此时,A线程暂停执行(阻塞),而B线程执行,直到B线程执行完毕后A线程继续执行
2. sleep()
sleep —— 让当前的正在执行的线程暂停指定的时间,并进入阻塞状态。在其睡眠的时间段内,该线程由于不是处于就绪状态,因此不会得到执行的机会。即使此时系统中没有任何其他可执行的线程,出于sleep()中的线程也不会执行。因此sleep()方法常用来暂停线程执行。
前面有讲到,当调用了新建的线程的start()方法后,线程进入到就绪状态,可能会在接下来的某个时间获取CPU时间片得以执行,如果希望这个新线程尽快执行,直接调用原来线程的sleep(1)即可。
(1)代码实例:
package test;
public class TestSleep {
public static void main(String[] args) {
for(int i=0; i<20; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
if(i == 10){
new Thread(new MySleep(), "MySleep").start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class MySleep implements Runnable{
@Override
public void run() {
for(int i=0; i<20; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
(2)运行结果:
main-->0
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9
main-->10
MySleep-->0
MySleep-->1
MySleep-->2
MySleep-->3
MySleep-->4
MySleep-->5
MySleep-->6
MySleep-->7
MySleep-->8
MySleep-->9
MySleep-->10
MySleep-->11
MySleep-->12
MySleep-->13
MySleep-->14
MySleep-->15
MySleep-->16
MySleep-->17
MySleep-->18
MySleep-->19
main-->11
main-->12
main-->13
main-->14
main-->15
main-->16
main-->17
main-->18
main-->19
3. 后台线程(Daemon Thread)
后台线程主要是为其他线程(相对可以称之为前台线程)提供服务,或“守护线程”。如JVM中的垃圾回收线程。
生命周期:后台线程的生命周期与前台线程生命周期有一定关联。主要体现在:当所有的前台线程都进入死亡状态时,后台线程会自动死亡(其实这个也很好理解,因为后台线程存在的目的在于为前台线程服务的,既然所有的前台线程都死亡了,那它自己还留着有什么用)。
设置后台线程:调用Thread对象的setDaemon(true)方法可以将指定的线程设置为后台线程。
(1)代码实例:
package test;
public class TestDeamon {
public static void main(String[] args) {
MyDeamon myDeamon = new MyDeamon();
Thread thread = new Thread(myDeamon, "MyDeamon");
for(int i=0; i<20; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
if(i == 5){
thread.setDaemon(true);
thread.start();
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(i >= 19){
System.out.println("main线程执行完毕");
}
}
}
}
class MyDeamon implements Runnable{
@Override
public void run() {
System.out.println("MyDeamon线程开始执行");
for(int i=0; i<100; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("MyDeamon线程执行完毕");
}
}
(2)运行结果:
main-->0
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
MyDeamon线程开始执行
main-->7
main-->8
main-->9
main-->10
main-->11
main-->12
main-->13
main-->14
main-->15
main-->16
main-->17
main-->18
main-->19
main线程执行完毕
MyDeamon-->0
判断线程是否是后台线程:调用thread对象的isDeamon()方法。
注:main线程默认是前台线程,前台线程创建中创建的子线程默认是前台线程,后台线程中创建的线程默认是后台线程。调用setDeamon(true)方法将前台线程设置为后台线程时,需要在start()方法调用之前。前天线程都死亡后,JVM通知后台线程死亡,但从接收指令到作出响应,需要一定的时间,前台线程main执行完毕后,后台线程收到指令结束线程,由于有一定的响应时间,所以执行了一段代码MyDeamon-->0
4. 改变线程的优先级/setPriority()
每个线程在执行时都具有一定的优先级,优先级高的线程具有较多的执行机会。每个线程默认的优先级都与创建它的线程的优先级相同。main线程默认具有普通优先级。
设置线程优先级:setPriority(int priorityLevel)。参数priorityLevel范围在1-10之间,常用的有如下三个静态常量值:
MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5
注:具有较高线程优先级的线程对象仅表示此线程具有较多的执行机会,而非优先执行。
(1)代码实例:
package test;
public class TestPriority {
public static void main(String[] args) {
MyPriority myPriority = new MyPriority();
Thread thread = new Thread(myPriority, "MyPriority");
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
for(int i=0; i<20; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
class MyPriority implements Runnable{
@Override
public void run() {
for(int i=0; i<20; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
(2)运行结果1:
MyPriority-->0
MyPriority-->1
MyPriority-->2
MyPriority-->3
MyPriority-->4
MyPriority-->5
MyPriority-->6
MyPriority-->7
MyPriority-->8
MyPriority-->9
MyPriority-->10
MyPriority-->11
MyPriority-->12
MyPriority-->13
MyPriority-->14
MyPriority-->15
MyPriority-->16
MyPriority-->17
MyPriority-->18
MyPriority-->19
main-->0
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9
main-->10
main-->11
main-->12
main-->13
main-->14
main-->15
main-->16
main-->17
main-->18
main-->19
运行结果2:
main-->0
MyPriority-->0
MyPriority-->1
MyPriority-->2
MyPriority-->3
MyPriority-->4
MyPriority-->5
MyPriority-->6
MyPriority-->7
MyPriority-->8
MyPriority-->9
MyPriority-->10
MyPriority-->11
MyPriority-->12
MyPriority-->13
MyPriority-->14
MyPriority-->15
MyPriority-->16
MyPriority-->17
MyPriority-->18
MyPriority-->19
main-->1
main-->2
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9
main-->10
main-->11
main-->12
main-->13
main-->14
main-->15
main-->16
main-->17
main-->18
main-->19
可以看到,当设置了线程优先级后,优先级高的具有较多的执行机会,但是并不一定优先执行,运行结果1和2有些许不同,1中MyPriority线程先执行,2中main线程先执行了一段时间,后让给优先级高的MyPriority线程,可见,证实了"具有较高线程优先级的线程对象仅表示此线程具有较多的执行机会,而非优先执行。"
5. 线程让步:yield()
使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。cpu会从众多的可执行态里选择,也就是说,当前也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说一定会执行其他线程而该线程在下一次中不会执行到了。调用yield方法后,该线程就会把CPU时间让掉,让其他或者自己的线程执行(也就是谁先抢到谁执行)
同时,yield()方法还与线程优先级有关,当某个线程调用yiled()方法从运行状态转换到就绪状态后,CPU从就绪状态线程队列中只会选择与该线程优先级相同或优先级更高的线程去执行。
(1)代码实例:
package test;
public class TestYield {
public static void main(String[] args) {
MyYield1 myYield1 = new MyYield1();
MyYield2 myYield2 = new MyYield2();
Thread thread1 = new Thread(myYield1, "MyYield1");
Thread thread2 = new Thread(myYield2, "MyYield2");
thread1.setPriority(Thread.MAX_PRIORITY);
thread2.setPriority(Thread.MIN_PRIORITY);
thread1.start();
thread2.start();
for(int i=0; i<50; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
if(i == 10){
Thread.yield();
}
}
}
}
class MyYield1 implements Runnable{
@Override
public void run() {
for(int i=0; i<30; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
class MyYield2 implements Runnable{
@Override
public void run() {
for(int i=0; i<30; i++){
System.out.println(Thread.currentThread().getName() + "-->" + i);
}
}
}
(2)运行结果:
main-->0
main-->1
main-->2
MyYield1-->0
MyYield1-->1
MyYield1-->2
MyYield1-->3
MyYield1-->4
MyYield1-->5
MyYield1-->6
MyYield1-->7
MyYield1-->8
MyYield1-->9
MyYield1-->10
MyYield1-->11
MyYield1-->12
MyYield1-->13
MyYield1-->14
MyYield1-->15
MyYield1-->16
MyYield1-->17
MyYield1-->18
MyYield1-->19
MyYield1-->20
MyYield1-->21
MyYield1-->22
MyYield1-->23
MyYield1-->24
MyYield1-->25
MyYield1-->26
MyYield1-->27
MyYield1-->28
MyYield1-->29
main-->3
main-->4
main-->5
main-->6
main-->7
main-->8
main-->9
main-->10
main-->11
main-->12
main-->13
main-->14
main-->15
main-->16
main-->17
main-->18
main-->19
main-->20
main-->21
main-->22
main-->23
main-->24
main-->25
main-->26
main-->27
main-->28
main-->29
main-->30
main-->31
main-->32
main-->33
main-->34
main-->35
main-->36
main-->37
main-->38
main-->39
main-->40
main-->41
main-->42
main-->43
main-->44
main-->45
main-->46
main-->47
main-->48
main-->49
MyYield2-->0
MyYield2-->1
MyYield2-->2
MyYield2-->3
MyYield2-->4
MyYield2-->5
MyYield2-->6
MyYield2-->7
MyYield2-->8
MyYield2-->9
MyYield2-->10
MyYield2-->11
MyYield2-->12
MyYield2-->13
MyYield2-->14
MyYield2-->15
MyYield2-->16
MyYield2-->17
MyYield2-->18
MyYield2-->19
MyYield2-->20
MyYield2-->21
MyYield2-->22
MyYield2-->23
MyYield2-->24
MyYield2-->25
MyYield2-->26
MyYield2-->27
MyYield2-->28
MyYield2-->29
多线程 java 实例_Java多线程实例学习相关推荐
- java多线程并发实例_JAVA多线程的并发控制|java多线程并发实例
java的多线程实现主要有两种,一种是继承Thread,一种是实现Runnable接口,这个是java最基本的多线程知识.这里要补充一下,runnable接口中的run方法是不返回任何内容的,如果想返 ...
- java 多线程 并发实例_Java 多线程(并发)
线程释义 使用java.lang.Thread类或者java.lang.Runnable接口编写代码来定义.实例化和启动新线程. 一个Thread类实例只是一个对象,像Java中的任何其他对象一样,具 ...
- 多线程java 银行_Java 多线程 之 银行ATM实例
package com.thread;import java.util.Scanner;public class TestBank { public static void main(String[] ...
- java多线程 cpu分配_java多线程总结(转载)
Java 多线程编程总结 --------------------------------------------------------------------------------------- ...
- java丐帮_Java多线程学习笔记(一)
一.什么是多线程 首先是多线程的概念: 多线程是异步的,和单任务不同,并不一定按照代码的执行顺序(上图左)来运行,而是交错占用CPU运行(上图右): 二.如何使用多线程 JAVA多线程有两种实现方式: ...
- java多线程读取文件_java多线程读写同一个文件
本文提供java多线程分别定时读写同一个文件的样例,其中两个线程,一个每分钟写入当前时间到指定文件,另一个线程读出每分钟新写的内容. 使用简单的Thread.sleep技术实现定时 package t ...
- python多线程爬虫实例-Python多线程在爬虫中的应用
题记:作为测试工程师经常需要解决测试数据来源的问题,解决思路无非是三种:(1)直接从生产环境拷贝真实数据 (2)从互联网上爬取数据 (3)自己用脚本或者工具造数据.前段时间,为了获取更多的测试数据,笔 ...
- python多线程爬虫实例-Python3多线程爬虫实例讲解代码
多线程概述 多线程使得程序内部可以分出多个线程来做多件事情,充分利用CPU空闲时间,提升处理效率.python提供了两个模块来实现多线程thread 和threading ,thread 有一些缺点, ...
- java中thread实例_Java多线程2:Thread中的实例方法
Thread类中的方法调用方式: 学习Thread类中的方法是学习多线程的第一步.在学习多线程之前特别提出一点,调用Thread中的方法的时候,在线程类中,有两种方式,一定要理解这两种方式的区别: 1 ...
最新文章
- 事务隔离机制原理分析以及是否可以防止订单超卖
- 用perl访问Oracle
- Flutter Text或者RichText不换行的问题
- Tomcat发布网页的方法记录
- sshd_config 中文手册
- 强行覆盖远程的gitlab 出错
- Html5开发-使用Canvas绘制图片
- html鼠标互动旋转立方体,css3 transform及原生js实现鼠标拖动3D立方体旋转的示例介绍...
- php颜色十六进制代码,如何通过PHP中的十六进制代码检索颜色的人名
- 钢材规格解读的软件_钢结构常用设计软件的总结与分析
- C语言中 字符串和数字的相互转换
- win7黑苹果双系统隐藏Clover多余启动项
- 10个值得珍藏的4K高清壁纸网站推荐
- hp服务器光盘安装win7系统安装教程,惠普win7系统安装方法,教您惠普win7系统怎么安装...
- 具有超能力的对话式机器人性能如何? #Chatsonic AI
- 2023美国大学生数学建模竞赛(美赛)思路代码
- 帧服务器支持会声会影哪个版本,会声会影哪个版本好用
- 分布式相关问题总结(精选)
- CAN网络应用软件设计CANoeCANFD
- 精心收藏的50个有用的PSD到HTML/CSS转换教程推荐给web开发人员
热门文章
- 嵩天-Python语言程序设计程序题--第九周:Python计算生态纵览
- 一文看懂:互联网产品分析,该如何做?
- csv 文件驱动的 jMeter 并发测试
- 关于前端开发 Framework Agnostic 和微前端的话题
- SAP Hybris - how to find corresponding cronjob for a given import
- 如何自定义SAP Spartacus 产品明细的url pattern
- Angular Service依赖注入的一个具体例子
- 使用扩展技术对SAP Fiori应用进行端到端的增强,一个实际案例介绍
- SAP Hybris Commerce installer目录下的build.gradle
- Netweaver和CloudFoundry的log设置