一:线程状态
1:线程状态的分类
1:线程的状态:
1.1:新生状态 : new
线程的新生状态就是在线程刚开始创建的时候
1.2:就绪状态
就绪状态表示等待cpu调度执行代码内容,代码进入就绪状态的方式如下
- start()
- 阻塞解除
- cpu的调度切换
- yield 礼让线程
1.3:运行状态 : cpu调度
只有在cpu将时间论片交给当前线程,执行当前线程方法的时候,当前线程才属于运行状态
1.4:阻塞状态
表示当前线程在执行代码的时候,有一段代码需要等待一段时间才可以继续响应 一个线程如果进入
到阻塞状态,阻塞解除之后,不能直接恢复到运行,会直接恢复高就绪状态,等待cpu的调度,
让线程进入阻塞状态如下:
- sleep()
- join() 插队线程
- wait() 等待
- IO 【流的操作较慢,需要等待内存运行一会,所以也属于阻塞状态】
1.5:终止状态
一个线程如果一旦进入终止状态,不可恢复,表示当前线程不在继续执行如何让线程进入终止状态:
- 正常执行完毕
- stop() 过时--> 不推荐使用
- 通过标识判断
二:线程Thread中的方法API
1:方法sleep
static void sleep(long millis) 导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,具体取决于系统计时器和调度程序的精度和准确性。
static void sleep(long millis, int nanos) 等待ms+ns【毫秒+纳秒】才能在被cpu调度执行
1.1方法sleep作用
/**
作用:
1:在某一段代码内添加slepp,可以增大几率在sleep方法处cpu调度到其他线程去执行
2:模拟网络延迟
*/
public class Class001_ThreadState implements Runnable{
public static void main(String[] args) {
//创建Thread,传递实现了Runnable接口的对象,然后调用start方法开启线程
new Thread(new Class001_ThreadState()).start();
}
@Override
public void run() {
for(int i=10;i>0;i--){
try {
//停留1秒,模拟倒计时
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("倒计时"+i);
}
}
}
2:线程礼让yield
当线程执行到yield方法,会让出cpu的资源,同时线程会恢复就绪状态
2.1礼让yield代码测试
public class Class002_Yield implements Runnable{
public static void main(String[] args) {
//创建实现了Runnable接口的线程对象
Class002_Yield cy = new Class002_Yield();
//创建Threa线程,传递线程对象,开启线程
new Thread(cy,"线程1").start();
new Thread(cy,"线程2").start();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"开始了");
//当线程代码执行到此处的时候,会释放cpu资源,让cpu再次重新调度,
//表示礼让【当然cpu有可能再次调度当前线程继续执行】
Thread.yield(); //礼让
System.out.println(Thread.currentThread().getName()+"结束了");
}
}
3:线程插队执行join
join() 插队线程: A线程执行过程中,如果B线程插队了,A线程就会进入到阻塞状态,等待插队线程执行完毕|等待执行的时间,A线程会恢复到就绪状态
void join() 等待这个线程死亡。
void join(long millis) 此线程最多等待 millis毫秒。
void join(long millis, int nanos) 此线程最多等待 millis毫秒加上 nanos纳秒。
3.1线程插队代码 Demo
/**
* 下面我们演示一个狠心的父亲,
* 在使用线程插队的时候需要注意,开始线程和插队方法join的位置,
* 如果在开启一个线程后,立马join插队【如大儿子】,那么就会等待当前插队线程执行完毕才会执行其他内容
* 如果在开启线程后,有其他代码,然后在插队,中间其他的代码也会一起执行【如二,三儿子同时开启】
*/
public class Class003_Join{
public static void main(String[] args) {
//只需要在主线程中开启父类线程
new Thread(new Father()).start();
}
}
class Father implements Runnable{
@Override
public void run() {
System.out.println("大儿子小白去搬砖挣钱");
//创建需要插队的线程对象
Thread one = new Thread(new SonOne());
Thread two = new Thread(new SonTwo());
Thread three = new Thread(new SonThree());
//需要先插队的线程先开启,大儿子的线程必须先执行完毕,才能让后面的子类线程或者父类中其他代码执行,所以在开启后,立马插队执行
one.start();
try {
//线程开启后使当前线程进行插队,不传递参数,表示一直等待此线程执行完毕,父线程才执行
one.join();
//插队的线程执行完毕,继续执行当前父线程
System.out.println("大儿子给的钱");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("大儿子挣的钱,给老父亲二儿子去买烟");
System.out.println("大儿子挣的钱,给老父亲三儿子去买酒");
//如果两个线程不分前后关系,可以一起开启,同时开启需要插队的线程
two.start();
three.start();
try {
//然后两个线程同时插队去执行
two.join();
three.join();
//后续代码必须等待二,三儿子线程执行完才能继续执行
System.out.println("获得到了二儿子和三儿子的烟和酒");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class SonOne implements Runnable{
@Override
public void run() {
System.out.println("我是大儿子,要去搬砖挣钱");
for (int i = 1; i < 5; i++) {
try {
System.out.println("搬砖中"+i+"天");
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class SonTwo implements Runnable{
@Override
public void run() {
System.out.println("我是二儿子,拿钱去买烟");
for (int i = 1; i <= 2; i++) {
try {
System.out.println("买烟"+i+"中");
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class SonThree implements Runnable{
@Override
public void run() {
System.out.println("我是三儿子,拿钱去买酒");
for (int i = 1; i <= 2; i++) {
try {
System.out.println("买酒"+i+"中");
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
4:中断标识interrupt
void interrupt() 为线程添加一个中断标识
boolean isInterrupted() 测试此线程是否已被中断,是否曾经调用过interrupt方法添加了中断标识
static boolean interrupted() 测试当前线程是否已被中断,是否曾经调用过interrupt方法添加了中断标识,同时复位标识
注意: 当调用sleep方法线程睡眠时 : InterruptedException - 如果有任何线程中断了当前线程,就会抛出此异常。 抛出此异常时,将清除当前线程的中断状态 。
4.1中断标识 Demo
public class Class004_Interrupt implements Runnable{
@Override
public void run() {
for(int i=1;i<=50;i++){
System.out.println(i+"---"+Thread.currentThread().isInterrupted());
if(Thread.interrupted()){//此方法判断如果中断标识为true,会修改为false[复位]
System.out.println("当前线程已被中断....");
System.out.println(Thread.currentThread().isInterrupted());
break;
}
/*try {
Thread.sleep(1); //如果在此线程sleep休眠的时候,中断标识被修改为true,sleep方法会抛出异常InterruptedException
} catch (InterruptedException e) {
e.printStackTrace();
}*/
}
}
public static void main(String[] args) throws InterruptedException {
Thread th = new Thread(new Class004_Interrupt());
System.out.println(th.isInterrupted());//中断表示刚开始为false
//开启线程
th.start();
Thread.sleep(1);//休眠一毫秒,增加cpu调度可能性
//此方法,为th线程添加中断标识,中断表示修改为true
th.interrupt();
}
}
5:获取当前线程状态getState
Thread.State 线程状态。 线程可以处于以下状态之一:
NEW : new Thread() 尚未启动的线程处于此状态。
RUNNABLE : 就绪|运行 在Java虚拟机中执行的线程处于此状态。
BLOCKED : 等待对象锁的阻塞状态 被阻塞等待监视器锁定的线程处于此状态。
WAITING : wait(),join()等 无限期等待另一个线程执行特定操作的线程处于此状态。
TIMED_WAITING : 与时间相关的等待,sleep(ms),join(ms),wait(ms)...
正在等待另一个线程执行最多指定等待时间的操作的线程处于此状态。
TERMINATED : 终止 已退出的线程处于此状态。
5.1:获取线程状态测试代码 Demo
public class Class005_getState implements Runnable{
@Override
public void run() {
for (int i=1;i<=20;i++){
System.out.println("i = "+i);
if(i==10){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args){
Thread th = new Thread(new Class005_getState());
System.out.println(th.getState()); //NEW
th.start();
System.out.println(th.getState());
while(true){
System.out.println("循环判断中 : "+th.getState());
//当th线程终止,循环结束
if(Thread.State.TERMINATED==th.getState()){
break;
}
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
6:线程优先级设置setPriority
线程的优先级 :
方法线程优先执行的可能性,只是增加了可能性,但是具体执行那个线程还是cpu调度来了,不一定优先级高的线程肯定比优先级低的线程先执行
1~10 设置值
1最小 ->static int MIN_PRIORITY 线程可以拥有的最低优先级。
10最大->static int MAX_PRIORITY 线程可以拥有的最大优先级。
5默认值 ->static int NORM_PRIORITY 分配给线程的默认优先级。
int getPriority() 返回此线程的优先级。
void setPriority(int newPriority) 更改此线程的优先级。
6.1线程优先级设置代码测试 Demo
public class Class006_Priority implements Runnable{
public static void main(String[] args) {
Class006_Priority cp = new Class006_Priority();
Thread th1 = new Thread(cp,"A");
Thread th2 = new Thread(cp,"B");
Thread th3 = new Thread(cp,"C");
th1.setPriority(1);
th2.setPriority(10);
th3.setPriority(Thread.MAX_PRIORITY);
//获取优先级
System.out.println(th1.getPriority());
System.out.println(th2.getPriority());
System.out.println(th3.getPriority());
th1.start();
th2.start();
th3.start();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"执行了.....");
}
}
7:守护线程设置 setDaemon
当所有的用户线程全都执行完毕,守护线程直接结束!!!【守护所有用户线程,不能制定守护某几个线程】
线程的分类:
用户线程 : 默认线程为用户线程
守护线程
守护线程 : 守护用户线程的
当所有的用户线程全都执行完毕,守护线程直接结束
垃圾回收机制典型守护线程
void setDaemon(boolean on) 将此线程标记为 daemon线程或用户线程。
7.1:守护线程代码设置
public class Class007_Daemon implements Runnable{
public static void main(String[] args){
Thread th = new Thread(new Class007_Daemon());
//设置守护线程
th.setDaemon(true);
th.start();
try {
Thread.sleep(30);//增加cpu调度机会
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程结束->表示所有用户线程结束");
}
@Override
public void run() {
int i = 1;
while(true){
System.out.println("守护线程............."+i);
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}