java并发编程基础—生命周期与线程控制
一、线程生命周期
线程被创建启动以后,他既不是一启动就进入执行状态,也不是一直处于执行状态,在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)五种状态

1、新建状态
当程序使用new关键字创建了一个线程后,该线程就处于新建状态
2、就绪状态
当线程对象调用了start()方法之后,该线程就处于就绪状态,java虚拟机会为其创建方法调用栈和程序计数器。
这个状态中的线程并没有开始执行线程,只是表示该线程可以运行了,至于何时运行,取决于JVM线程调度器调度。
3、运行状态
如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态。
4、阻塞状态
当运行状态的线程发生如下情况时,线程会进入阻塞状态:
(1)线程调用sleep()方法主动放弃所占用的处理器资源。
(2)线程调用了一个阻塞式IO方法,在该方法返回之前,该线程被阻塞
(3)线程试图获得一个同步监视器,但该同步监视器正被其他线程所持有。
(4)线程在等待某个通知(notify)
(5)程序调用了线程的suspend()方法将线程挂起,这个方法在jdk1.6中已经过时,它容易导致死锁,不建议使用。
针对上面阻塞状态,当发生下面特定情况可以解除阻塞状态:
(1)sleep()方法经过了指定时间。
(2)阻塞式IO方法已经返回
(3)线程成功获得了一个同步监视器。
(4)线程在等待某个通知时,其他线程发出了一个通知
(5)处于挂起的线程被调用了resume()恢复方法
5、线程死亡
线程结束后就处于死亡状态,有三种结束方式:
(1)run()或call()方法执行完成,线程正常结束
(2)线程抛出一个未捕获的Exception或者Error
(3)直接调用线程的stop()方法结束线程——容易死锁,不建议使用
isAlive()方法可以判断线程是否死亡,当处于就绪、运行、阻塞状态时返回true,处于新建、死亡状态时返回false。
已经死亡的线程不能重新启动,否则引发IllegalThreadStateException。
二、控制线程
java线程提供了一些简便的工具方法,利用这些方法可以很好的控制线程
1、join()
join()方法:让一个线程等待一个线程完成。
package threadtest;
public class ThreadTest implements Runnable {
@Override
public void run() {
for(int i=0;i<30;i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
} } public static void main(String[] args) throws InterruptedException { ThreadTest target1 = new ThreadTest();
Thread t1 = new Thread(target1,"t1");
t1.start();
for(int i=0;i<30;i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
//开始主线程和t1线程并发执行,当main线程的i到15时,调用了t1线程的join方法,
//此时主线程等待t1线程,直到t1结束时才跑main,
//join后,主线程处于阻塞状态
if(i == 15) {
t1.join();
}
}
} }
2、线程睡眠 sleep()
如果需要让当前线程暂停一段时间,则可以使用sleep()方法
package threadtest;
import java.time.LocalTime;
public class ThreadTest implements Runnable {
@Override
public void run() {
for(int i=0;i<30;i++) {
System.out.println(Thread.currentThread().getName() + " " + i +" "+ LocalTime.now());
if(i == 15){
try {
Thread.sleep(10000);//10s
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
ThreadTest target1 = new ThreadTest();
Thread t1 = new Thread(target1,"t1");
t1.start();
}
}
3、线程让步 yield()
yield()方法会让线程直接进入就绪状态,主要作用就是让当前线程暂停一下。完全有可能线程yield()后,线程调度器又将该线程调度出来执行。
yield()暂停后,只有优先级与当前线程相同或者优先级比当前线程更高的处于就绪状态的线程才有机会获得执行机会。
package threadtest;
import java.time.LocalTime;
public class ThreadTest implements Runnable {
@Override
public void run() {
for(int i=0;i<30;i++) {
System.out.println(Thread.currentThread().getName() + " " + i +" "+ LocalTime.now());
if(i == 15){
Thread.yield();//线程让步
}
}
}
public static void main(String[] args) throws InterruptedException {
ThreadTest target1 = new ThreadTest();
Thread t1 = new Thread(target1,"t1");
t1.start();
for(int i=0;i<10;i++) {
System.out.println(Thread.currentThread().getName() + " " + i +" "+ LocalTime.now());
}
}
}
sleep()和yield()方法的区别
(1)sleep暂停后会给其他线程机会,不会理会其他线程的优先级,但yield只给优先级相同或者更高的线程机会
(2)sleep将线程转为阻塞状态,yield将线程转为就绪状态
(3)sleep方法声明抛出了InterruptedException异常,所以用sleep要么捕捉该异常,要么抛出该异常。
(4)sleep比yield有更好的移植性,通常不建议使用yield方法来控制并发线程的执行
线程的优先级
每个线程执行时都有一定的优先级,优先级高的线程能获得更多的执行机会。每个线程的默认优先级与创建它的父线程优先级相同。默认情况下,main线程具有普通优先级
Thread类中 setPriority(int newPriority)和getPriority()方法分别设置和获取线程的优先级。
setPriority(int newPriority)的参数是一个整数,范围1-10;也可以是三个静态常量
MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5
package threadtest;
import java.time.LocalTime;
public class ThreadTest implements Runnable {
@Override
public void run() {
for(int i=0;i<30;i++) {
System.out.println(Thread.currentThread().getName() + " " + i +" "+ LocalTime.now());
if(i == 15){
Thread.yield();
}
}
}
public static void main(String[] args) throws InterruptedException {
ThreadTest target1 = new ThreadTest();
Thread t1 = new Thread(target1,"t1");
Thread t2 = new Thread(target1,"t2");
t2.setPriority(Thread.MAX_PRIORITY);//设置优先级
t1.start();
t2.start();
}
}
java并发编程基础—生命周期与线程控制的更多相关文章
- Java并发1——线程创建、启动、生命周期与线程控制
内容提要: 线程与进程 为什么要使用多线程/进程?线程与进程的区别?线程对比进程的优势?Java中有多进程吗? 线程的创建与启动 线程的创建有哪几种方式?它们之间有什么区别? 线程的生命周期与线程控制 ...
- Java并发编程基础
Java并发编程基础 1. 并发 1.1. 什么是并发? 并发是一种能并行运行多个程序或并行运行一个程序中多个部分的能力.如果程序中一个耗时的任务能以异步或并行的方式运行,那么整个程序的吞吐量和可交互 ...
- 并发-Java并发编程基础
Java并发编程基础 并发 在计算机科学中,并发是指将一个程序,算法划分为若干个逻辑组成部分,这些部分可以以任何顺序进行执行,但与最终顺序执行的结果一致.并发可以在多核操作系统上显著的提高程序运行速度 ...
- Java并发编程(您不知道的线程池操作), 最受欢迎的 8 位 Java 大师,Java并发包中的同步队列SynchronousQueue实现原理
Java_并发编程培训 java并发程序设计教程 JUC Exchanger 一.概述 Exchanger 可以在对中对元素进行配对和交换的线程的同步点.每个线程将条目上的某个方法呈现给 exchan ...
- Java并发编程--基础进阶高级(完结)
Java并发编程--基础进阶高级完整笔记. 这都不知道是第几次刷狂神的JUC并发编程了,从第一次的迷茫到现在比较清晰,算是个大进步了,之前JUC笔记不见了,重新做一套笔记. 参考链接:https:// ...
- Java并发编程(您不知道的线程池操作)
Java并发编程(您不知道的线程池操作) 这几篇博客,一直在谈线程,设想一下这个场景,如果并发的线程很多,然而每个线程如果执行的时间很多的话,这样的话,就会大量的降低系统的效率.这时候就可以采用线程池 ...
- 【Java并发编程】之二:线程中断
[Java并发编程]之二:线程中断 使用interrupt()中断线程 当一个线程运行时,另一个线程可以调用对应的Thread对象的interrupt()方法来中断它,该方法只是在目标线程中设置一 ...
- java并发编程笔记(七)——线程池
java并发编程笔记(七)--线程池 new Thread弊端 每次new Thread新建对象,性能差 线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或者OOM 缺 ...
- java并发编程笔记(五)——线程安全策略
java并发编程笔记(五)--线程安全策略 不可变得对象 不可变对象需要满足的条件 对象创建以后其状态就不能修改 对象所有的域都是final类型 对象是正确创建的(在对象创建期间,this引用没有逸出 ...
随机推荐
- Paddle Release Note
Paddle Release Note 重要更新 飞桨paddle框架2.0.0版本有如下重要更新: 编程范式:默认开启动态图模式进行模型开发和训练,通过动转静的方式进行模型部署和训练加速.如果需要使 ...
- python+selenium基础篇,文件上传
1.百度查询图片,上传文件 2.实现代码如下: from selenium import webdriverfrom time import sleepdr=webdriver.Firefox()dr ...
- 狂神说redis笔记(一)
一.Nosql概述 1.单机Mysql时代 90年代,一个网站的访问量一般不会太大,单个数据库完全够用.随着用户增多,网站出现以下问题: 数据量增加到一定程度,单机数据库就放不下了 数据的索引(B+ ...
- springboot静态资源映射规则
一.所有/webjars/**的请求,都会去classpath:/META-INF/resources/webjars/下的目录去找资源. 二.访问/**,即访问任何资源,如果没有controller ...
- 搭建 MySQL 高可用高性能集群
什么是MySQL集群,什么是MySQL集群,如果你想知道什么是MySQL集群,我现在就带你研究. MySQL 是一款流行的轻量级数据库,很多应用都是使用它作为数据存储.作为小型应用的数据库,它完全可以 ...
- 来了!STM32移植LuatOS,潘多拉示例全新教程
进击的五月,继上期<使用Air724UG制作简易贪吃蛇>教程之后,@打盹的消防车 又为大家带来基于STM32的潘多拉LuatOS移植全新教程: 为什么使用潘多拉作为教程呢? STM32不能 ...
- Python使用websocket调用语音识别,语音转文字
@ 目录 0. 太长不看系列,直接使用 1. Python调用标贝科技语音识别websocket接口,实现语音转文字 1.1 环境准备: 1.2 获取权限 1.2.1 登录 1.2.2 创建新应用 1 ...
- 拦截导弹(CDQ分治,DP)
很好的题,值得细细说,(果然又是个假期望)....... 首先我们提取信息,显然这是个三维偏序问题 用简单的DP式子表示需要满足 f[i]=max(f[1--j]+1)(v[j]<v[i],h[ ...
- SQL 利用存储过程实现对表数据有则更新无则添加(转)
初学存储过程,发现这篇文章简单易懂,特意转载,地址 http://blog.csdn.net/luotuomianyang/article/details/52013144 如果某一操作包含大量的T- ...
- 写DockerFile的一些技巧
Docker镜像由只读层组成,每个层都代表一个Dockerfile指令.这些层是堆叠的,每一层都是前一层变化的增量.示例Dockerfile: FROM ubuntu:15.04 COPY . / ...