【JavaSE】多线程3

本文详细介绍了Java线程的生命周期状态,包括新建、就绪、运行、阻塞和死亡,并展示了如何通过setPriority、sleep、join、yield和interrupt等方法控制线程行为。此外,还讲解了线程停止的最佳实践,即使用标志位而非stop方法。通过实例代码,演示了线程休眠、礼让、强制执行join和观察线程状态的方法。最后,提到了线程优先级和守护线程的概念及其应用。
摘要由CSDN通过智能技术生成

线程状态

创建状态:new一个线程
就绪状态:开始start方法
运行状态:CPU调度完成
阻塞状态:CPU调度之后未执行完
死亡状态:线程执行完之后
在这里插入图片描述
在这里插入图片描述

-线程方法

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

-线程停止

不推荐使用JDK提供的stop()、destroy()方法来停止线程
推荐让线程自己停下来
建议使用一个标志位进行终止变量,当flag = false,则终止线程

//测试stop
/*
    1.建议线程正常停止 ---> 定义利用次数,不建议死循环
    2.建议使用标志位 ---> 设置一个标志位,向外部提供修改标志的方法
    3.不要使用stop或者destroy等过时或JDK不建议使用的方法
 */
public class TestStop implements Runnable{

    //设置一个标志位
    private boolean flag = true;

    @Override
    public void run() {
        int i = 0;
        while(flag){
            System.out.println("run... Thead " + i++);
        }
    }

    //2.设置一个公开的方法停止线程,来转换标志位
    public void stop(){
        this.flag = false;
    }

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

        for (int i = 0; i < 1000; i++) {
            System.out.println("main " + i);
            if(i == 900){
                //3.调用stop方法改变标志位,来停止线程
                testStop.stop();
                System.out.println("线程该停止了");
            }
        }
    }
}

-线程休眠 sleep

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

实例1

//模拟网络延时放大问题的发生性
//模拟抢票
public class TestSleep implements Runnable{
    private int ticket = 50;

    @Override
    public void run() {
        while(true){  //模拟人们一直抢票的动作

            //模拟延时,减慢人们的抢票速度
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if(ticket <= 0) {  //票被抢完就退出程序
                System.out.println("ticket has none!");
                break;
            }

            System.out.println(Thread.currentThread().getName() + " 抢到了第 " + ticket-- + "张票");
        }
    }

    public static void main(String[] args) {
        //创建一个线程的实现对象
        TestSleep testSleep = new TestSleep();
        //多线程共享一个对象
        new Thread(testSleep,"小明").start();
        new Thread(testSleep,"张三").start();
        new Thread(testSleep,"小李").start();
        new Thread(testSleep,"王五").start();
        
        //可能会出现抢到同一张票的情况,线程是不安全的
    }
}

实例2

//模拟倒计时,打印系统时间
public class TestSleep2 {

    public static void main(String[] args) {
        TestSleep2 t2 = new TestSleep2();
//        try {  //倒计时方法
//            t2.timeDown(20);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

        Date startTime; //获取当前系统时间
        while(true){
            startTime = new Date(System.currentTimeMillis()); //获取当前系统时间
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void timeDown(int time) throws InterruptedException {
        while (true){
            Thread.sleep(1000);
            System.out.println(time--);
            if (time <= 0) break;
        }
    }
}

-线程礼让 yield

礼让线程,让当前正在运行的线程暂停,但是不阻塞
将线程从运行状态转换为就绪状态
yield方法会让CPU重新调度,但是礼让是不一定成功的

//测试礼让线程
//礼让不一定成功,要看CPU具体的调度
public class TestYield{

    public static void main(String[] args) {

        new Thread(() -> {  //Lambda表达式,简写Runnable函数式接口
            System.out.println(Thread.currentThread().getName() + " Thread Start");
            //Thread.yield(); //调用线程的礼让
            System.out.println(Thread.currentThread().getName() + " Thread Stop");
        },"A").start();

        new Thread(() -> {  //Lambda表达式,简写Runnable函数式接口
            System.out.println(Thread.currentThread().getName() + " Thread Start");
            //Thread.yield(); //调用线程的礼让
            System.out.println(Thread.currentThread().getName() + " Thread Stop");
        },"B").start();

        MyYield myYield = new MyYield();
        new Thread(myYield,"一").start();
        new Thread(myYield,"二").start();

    }
}

class MyYield implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " 线程开始");
        Thread.yield();
        System.out.println(Thread.currentThread().getName() + " 线程结束");
    }
}

/*某一次输出结果
	A Thread Start
	二 线程开始
	一 线程开始
	A Thread Stop
	B Thread Start
	二 线程结束
	B Thread Stop
	一 线程结束
*/

-线程强制执行 join

Join合并线程,等待此线程执行完成后,再执行其它线程
可以想象为插队

//测试join方法,想象为插队
public class TestJoin {
    public static void main(String[] args) throws InterruptedException {
        //启动定义的线程
//        VIP vip = new VIP();
//        Thread thread = new Thread(vip);
//        thread.start();

        //简化写法
        Thread thread = new Thread(()->{
            for (int i = 0; i <= 20; i++) {
                new MySleep().Asleep(300);   //模拟插队线程执行很慢造成阻塞
                System.out.println("VIP run..." + i);
            }
        });
        thread.start();

        //主线程
        for (int i = 0; i <= 10; i++) {
            if(i == 5) thread.join();  //主程序执行一半,让VIP线程插队
            System.out.println("main run... " + i);
        }
    }
}

//class VIP implements Runnable{
//    @Override
//    public void run() {
//        for (int i = 0; i <= 20; i++) {
//            new MySleep().Asleep(100);
//            System.out.println("VIP run..." + i);
//        }
//    }
//}

-线程的状态观测 Thread.state

线程状态,线程可以处于以下状态之一:

  • NEW:尚未启动的线程状态
  • RUNNABLE:在Java虚拟机中执行的线程处于此状态。
  • BLOCKED:被阻塞等待监视的线程处于此状态。
  • WAITING:正在等待另一个线程执行特定动作的线程的状态。
  • TIMED_WAITING:正在等待另一个线程执行动作达到指定等待时间的线程的状态。
  • TERMINATED:已退出的线程处于的状态
//观察测试线程的状态
public class TestState {
    public static void main(String[] args) {
        Thread thread = new Thread(()-> {
            for (int i = 0; i < 5; i++) {
                new MySleep().Asleep(1000);
                System.out.println("running....");
            }
        });

        //1.观察线程NEW状态
        Thread.State state = thread.getState();
        System.out.println(state);   //输出:NEW

        //2.观察线程启动后状态
        thread.start();  //启动线程
        state = thread.getState();
        System.out.println(state);

        while(state != Thread.State.TERMINATED){  //只要线程不终止就一直输出状态
            new MySleep().Asleep(500);  //模拟延迟
            state = thread.getState();        //更新状态
            System.out.println(state);        //打印状态
        }
        //thread.start();  //报错:java.lang.IllegalThreadStateException
        //死亡之后的线程不能再启动
    }
}

-线程的优先级

Java提供一个线程调度器来监控程序中启动后就进入状态的所有线程,线程调度器按照优先级决定应该调度哪一个线程来执行。线程优先级用数字表示,范围1~10

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

可用getPriority()来获取优先级
可用setPriority(int xx)来设置优先级

//测试优先级
public class PriorityTest {
    public static void main(String[] args) {
        //输出主线程默认优先级
        System.out.println(Thread.currentThread().getName() + " >> " + Thread.currentThread().getPriority());

        //创建线程
        MyPriority myPriority = new MyPriority();
        Thread t1 = new Thread(myPriority);
        Thread t2 = new Thread(myPriority);
        Thread t3 = new Thread(myPriority);
        Thread t4 = new Thread(myPriority);
        Thread t5 = new Thread(myPriority);
        Thread t6 = new Thread(myPriority);
        //设置优先级再启动
        t1.start();
        t2.setPriority(4);
        t2.start();
        t3.setPriority(8);
        t3.start();
        t4.setPriority(Thread.MIN_PRIORITY);  //MIN_PRIORITY = 1
        t4.start();
        t5.setPriority(Thread.MAX_PRIORITY);  //MAX_PRIORITY = 10
        t5.start();
        t6.setPriority(Thread.NORM_PRIORITY); //NORM_PRIORITY = 5
        t6.start();
        //设置优先级高不一定就先执行,还是要看CPU的具体调度
        
    }
}

class MyPriority implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " >> " + Thread.currentThread().getPriority());
    }
}

-守护线程 daemon

线程分为用户线程守护线程
虚拟机必须确保用户线程执行完毕
虚拟机不用等待守护线程执行完毕
守护线程其实很多:后台记录操作日志,监控内存,垃圾回收等,都是守护线程

//守护线程测试 上帝守护你
public class DaemonTest {
    public static void main(String[] args) {
        //创建线程的实例对象
        God god = new God();
        Human human = new Human();

        Thread thread = new Thread(god);
        thread.setDaemon(true); //系统默认所有的线程都是用户线程,只有设置才能称为守护线程
        thread.start();

        new Thread(human).start(); //默认为用户线程
    }
}

//上帝线程
class God implements Runnable{
    @Override
    public void run() {
        while(true){   //上帝线程一直守护执行,没有尽头。
            //但是设置守护线程之后,虚拟机就不会确保他是否执行完
            System.out.println("God守护你!");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

//人类线程
class Human implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i <= 36500; i++) {    //人类的线程存活的时间有限,终究会执行完成
            System.out.println("You are alive " + i + "Days");
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("-=====Good Bye World!=====-");  //人类线程执行完成,退出程序
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值