Java 多线程开发 04 —— 线程状态控制、优先级、守护线程

系列文章目录

Java 多线程开发 01 —— 线程创建
Java 多线程开发 02 —— 静态代理模式
Java 多线程开发 03 —— Lambda表达式
Java 多线程开发 04 —— 线程状态控制、优先级、守护线程
Java 多线程开发 05 —— synchronized、Lock、死锁
Java 多线程开发 06 —— 管程法、信号灯法



Java 线程的状态及控制


线程分为以下五个状态:

线程五个状态

五种状态具体解释:

线程状态解释    
方法 说明
void setPriority(int newPriority) 更改线程的优先级
static void sleep(long millis) 在指定的毫秒数内让当前线程休眠
void join() 等待该线程终止
static void yield() 暂停当前正在执行的线程,并执行其他线程
void interrupt() 中断线程(不推荐用这个方式中断)
boolean isAlive() 测试线程是否处于活动状态

停止线程

  • 不推荐使用JDK提供的 stop()、destroy() 等过时方法
  • 建议线程正常停止——利用次数,不建议死循环
  • 建议使用标志位——设置一个标志位
package lessen06;

public class TestThreadStop implements Runnable {
    
    
    private boolean flag = true;//标志位

    @Override
    public void run() {
    
    
        int count = 1;
        while (flag){
    
    
            System.out.println("run——>"+(count++));
        }
    }
	
    //给一个可以修改标志位的方法
    public void stop(){
    
    
        flag = false;
    }

    public static void main(String[] args) {
    
    
        TestThreadStop threadStop = new TestThreadStop();
        new Thread(threadStop).start();


        for (int i = 0; i < 1000; i++) {
    
    
            System.out.println("main——>"+i);
            if (i == 900){
    
    
                System.out.println("run()停止了");
                //外部通过调用该方法停止线程
                threadStop.stop();
            }
        }
    }
}

线程休眠 sleep()

  • sleep( 时间 ) 指定当前线程阻塞的毫秒数
  • sleep存在异常 InterruptedException
  • sleep时间达到后线程进入就绪状态
  • sleep可以模拟网络延时,倒计时等
  • 每一个对象都有一个锁,sleep不会释放锁

利用 sleep() 获取当前时间:

package lessen06;

import java.text.SimpleDateFormat;
import java.util.Date;

public class TestThreadSleep implements Runnable{
    
    

    @Override
    public void run() {
    
    
        Date startTime = new Date(System.currentTimeMillis());//获取系统当前时间
        while(true){
    
    
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
            startTime = new Date(System.currentTimeMillis());//更新系统当前时间
        }
    }
    public static void main(String[] args) {
    
    
        new Thread(new TestThreadSleep()).start();
    }
}

线程礼让 yield()

  • 礼让线程,即让当前运行状态的线程转为就绪状态
  • 让CPU重新调度,但不一定成功。
线程礼让

测试代码:

package lessen06;

public class TestThreadYield {
    
    
    public static void main(String[] args) {
    
    
        MyYield myYield = new MyYield();
        new Thread(myYield, "A").start();
        new Thread(myYield, "B").start();
    }
}

class MyYield implements Runnable{
    
    
    @Override
    public void run() {
    
    
        System.out.println(Thread.currentThread().getName()+"开始执行");
        Thread.currentThread().yield();//当前线程礼让
        System.out.println(Thread.currentThread().getName()+"停止执行");
    }
}

结果:

礼让成功:					未礼让:
    A开始执行					A开始执行
    B开始执行					A停止执行
    A停止执行					B开始执行
    B停止执行					B停止执行

注意:礼让可能会不成功,主要看CPU调度

线程强制执行 join()

说的通俗点就是让某个线程插队,直到该线程执行完,其它线程才能执行。

直接上代码:

package lessen06;

public class TestThreadJoin {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    
       	//插队线程 这里用了Lambda表达式
        Thread thread = new Thread(()->{
    
    
            for (int i = 0; i < 500; i++) {
    
    
                System.out.println("我是VIP,我先来"+i);
            }
        });
        thread.start();

        //主线程
        for (int i = 0; i < 500; i++) {
    
    
            if (i == 300)
                thread.join();
            System.out.println("main——>"+i);
        }
    }
}

Lambda表达式参考我另一篇博客 Java 多线程开发 03 —— Lambda表达式

线程状态观察

线程的状态包括:

  • NEW :尚未启动的线程
  • RUNNABLE:在Java虚拟机执行的线程
  • BLOCKED:被阻塞的等待监视器锁定的线程
  • WAITING:正在等待另一个线程执行的线程
  • TIMED_WAITING:等待另一给被指定执行等待时间的线程
  • TERMINATED:已终止的线程

可以通过Thread的getState()方法获取到一个Thread.State类型。

package lessen06;

import com.sun.org.apache.bcel.internal.generic.NEW;

public class TestThreadState {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        //线程体就是延时3s,方便观察状态,此时线程刚创建,是新生状态
        Thread thread = new Thread(()->{
    
    
                try {
    
    
                    Thread.sleep(300);// WAITING 阻塞状态
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
        });
        Thread.State state = thread.getState();
        System.out.println(state);//  NEW 新生状态

        thread.start();
        state = thread.getState();
        System.out.println(state);//  RUNNABLE 运行状态

        //一直运行,直到出现线程终止状态
        while(state != Thread.State.TERMINATED){
    
    
            Thread.sleep(100);
            state = thread.getState();
            System.out.println(state);
        }
    }
}

打印结果:

NEW
RUNNABLE
TIMED_WAITING
TIMED_WAITING
TERMINATED

这里最后会打印 TERMINATED ,因为我线程体延时300毫秒,main中的while每次会延时100毫秒,而run()先在while前面运行,当run()运行结束时,while还停留在Thread.sleep(100)中,此时再更新状态才是线程终止,所以能打印出 TERMINATED。

线程优先级

Java线程的优先级用数字表示,从1~10,这三个是默认的:

  • Thread.MIN_PRIORITY = 1;
  • Thread.MAX_PRIORITY = 10;
  • Thread.NORM_PRIORITY = 1;

通过 getPriority() 、setPriority(int)来获取和设置优先级。

注意:优先级低只是意味着获得调度的概率低,可能CPU也会先调用优先级低的,这就是性能倒置。但大多数情况还是先调用优先级高的。同时,设置优先级要在 start() 前面

守护线程 daemon

  • 线程分为用户线程守护线程
  • 虚拟机必须确保用户线程执行完毕
  • 虚拟机无需确保守护线程执行完毕
  • 守护线程例如:后台记录操作日志、监控内存、垃圾回收等

通过 setDaemon( boolean ) 来给一个线程设置为守护线程。

下面上帝线程里是死循环,但当用户线程,即you执行完毕时虚拟机就关闭了,上帝线程也会自动结束。(最后虚拟机关闭需要一定时间,上帝线程会活到虚拟机关闭)

package lessen06_Thread;

public class TestThreadDaemon {
    
    
    public static void main(String[] args) {
    
    
        //这里用了Lambda表达式
        Thread god = new Thread(()->{
    
    
            while(true){
    
    
                System.out.println("上帝正守护者你");
                try {
    
    
                    Thread.sleep(5);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        });
        god.setDaemon(true);//设置上帝为守护线程
		//这里用了Lambda表达式
        Thread you = new Thread(()->{
    
    
            for (int i = 1; i <= 100; i++) {
    
    
                System.out.println("这是你被守护的第 "+i+" 天");
                try {
    
    
                    Thread.sleep(10);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
            }
        });

        god.start();
        you.start();
    }
}

猜你喜欢

转载自blog.csdn.net/qq_39763246/article/details/112917363