线程状态

  线程驱动任务(任务在线程中执行)。线程可以是以下5种状态:新建、就绪、运行、阻塞或结束。

  新创建一个线程时,它就进入新建状态(New)。

  调用线程的start()方法启动线程后,它就进入就绪状态(Ready)。就绪状态是可运行的,但可能还没有开始运行,操作系统必须为它分配cpu时间。

  就绪线程开始运行时,它就进入运行状态,如果给定的CPU时间用完或调用线程的yield()方法,处于运行状态的线程可能进入就绪状态。

  有几种原因可能使线程进入阻塞状态(即非活动状态)。可能使它自己调用了join()、sleep()或wait()方法。它可能在等待I/O操作的完成。当使得其处于非激活状态的动作不起作用时,阻塞线程可能被重新激活。例如,如果线程处于休眠状态并且休眠时间已过期。

  最后,如果一个线程执行完它的run()方法,这个线程就被结束(finished)。

  isAlived()方法是用来判断线程状态的方法。如果线程处于就绪、阻塞或者运行状态,返回true;如果线程处于新建且没有启动,或者已经结束,返回返回。

  interrupt()方法中断一个线程:当线程处于就绪或者运行状态时,给它设置一个中断标志;当线程处于阻塞状态时,它将被唤醒并进入就绪状态,同时抛出异常java.lang.InterruptedException.

yield()方法为其它线程临时让出cpu时间。

  • 礼让线程,让当前正在执行线程暂停

  • 不是阻塞线程,而是将线程从运行 状态转入就绪状态

  • 让cpu调度器重新调度

复制代码
class PrintNum implements Runnable{
    private int count;
    public PrintNum(int count) {
        this.count = count;
    }
    @Override
    public void run() {
        for(int i = 0; i < count; i++) {
            System.out.println(" " + i);
            /*
             *yield()方法为其它线程临时让出cpu时间:
             *         让当前正在执行线程暂停,不是阻塞线程,而是将线程转入就绪状态
             *         调用了yield方法之后,如果没有其他等待执行的线程,此时当前线程就会马上恢复执行 
             */
            Thread.yield();//每打印一个数字后,该任务的线程会让出时间给其它线程
        }
    }
}
复制代码

sleep()将该线程设置为休眠以确保其它线程的执行,休眠时间为指定的毫秒数。

  • sleep(时间)指定当前线程阻塞的毫秒数;

  • sleep存在异常InterruptedException;

  • sleep时间达到后线程进入就绪状态;

  • sleep可以模拟网络延时、倒计时等。

  • 每一个对象都有一个锁,sleep不会释放锁;

复制代码
public class Racer implements Runnable {
    private String victor;
    @Override
    public void run() {
        for(int steps = 1; steps <= 100; steps++) {
            System.out.println(Thread.currentThread().getName() + "跑了:" + steps);
            if(steps % 20 == 0 && Thread.currentThread().getName().equals("rabbit")) {
                try {
            //使线程停止运行一段时间,将处于阻塞状态;如果调用了sleep方法之后,没有其他等待执行的线程,这个时候当前线程不会马上恢复执行! Thread.sleep(
1000); } catch (InterruptedException e) { e.printStackTrace(); } } if(gameOver(steps)) { System.out.println("比赛结束"); break; } } } //比赛是否结束 public boolean gameOver(int steps) { if(victor != null) return true; if(steps == 100) { victor = Thread.currentThread().getName(); System.out.println("胜利者===>" + victor); return true; } return false; } public static void main(String[] args) { Racer racer = new Racer(); new Thread(racer,"tortoise").start(); new Thread(racer,"rabbit").start(); } }
复制代码

join()方法使一个线程等待另一个线程的结束(其他线程阻塞)。

复制代码
public class BuyCigarettes {

    public static void main(String[] args) {
        Thread father = new Father();
        father.start();
    }

    private static class Father extends Thread {
        @Override
        public void run() {
            try {
                System.out.println("爸爸想抽烟,发现没有了");
                System.out.println("叫来儿子,给你100块买包中华");
                Thread son = new Son();
                son.start();
                //老爸想抽烟,需要等待儿子买烟回来(儿子线程执行完毕)
                son.join();
                System.out.println("爸爸接过烟,对你把头点");
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("儿子去哪了");
            }
        }
    }

    private static class Son extends Thread {
        @Override
        public void run() {
            try {
                System.out.println("接过老爸的人民币,屁颠颠出门了");
                System.out.println("发现路边有洗脚城,做个大宝剑:10秒钟");
                for (int i = 0; i < 10; i++) {
                    System.out.println(i + "秒过去了");
                    Thread.sleep(1000);
                }
                System.out.println("赶紧买烟去");
                System.out.println("手拿一包中华回家了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
复制代码

priority

  Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程。线程调 度器按照线程的优先级决定应调度哪个线程来执行。

  线程的优先级用数字表示,范围从1到10

    • Thread.MIN_PRIORITY = 1

    • Thread.MAX_PRIORITY = 10

    • Thread.NORM_PRIORITY = 5

  使用下述方法获得或设置线程对象的优先级。

    • int getPriority();

    • void setPriority(int newPriority);

  优先级的设定建议在start()调用前

  注意:优先级低只是意味着获得调度的概率低。并不是绝对先调用优先级高后调 用优先级低的线程。 

  提示:如果总有一个优先级较高的线程在运行,或者有一个相同优先级的线程不退出,name这个线程可能永远没有运行的机会。这种情况称为资源竞争。为了避免资源竞争,高优先级的线程必须定时的调用sleep或yield方法,来给低优先级或者相同优先级线程的运行机会。

setDaemon()

  • 线程分为用户线程和守护线程;

  • 虚拟机必须确保用户线程执行完毕;

  • 虚拟机不用等待守护线程执行完毕;

  • 如后台记录操作日志、监控内存使用等。

复制代码
public class DaemonTest {

    public static void main(String[] args) {
        God god = new God();
        You you  = new You();
        Thread t =new Thread(god);        
        t.setDaemon(true);//将用户线程调整为守护
        t.start();
        new Thread(you).start();
    }

}
class You implements Runnable{
    @Override
    public void run() {
        for(int i = 1;i <= 365 * 200; i++) {
            System.out.println("happy life...");
        }
        System.out.println("ooooo.....");
    }
}
class God implements Runnable{
    @Override
    public void run() {
        for(;;) {
            System.out.println("God bless you...");
        }
    }
}
复制代码

线程停止

  • 不使用JDK提供的stop()/destroy();suspend()/resume()方法(它们本身也被JDK废弃了)。

  • 提供一个boolean型的终止变量,当这个变量置为false,则终止线程的运行;或者给Thread变量赋值null表明它已经停止。

复制代码
public class TerminateThread implements Runnable {
    //1、加入标识 标记线程体是否可以运行
    private boolean flag = true;    
    private String name; 

    public TerminateThread(String name) {
        this.name = name;
    }
    @Override
    public void run() {
        int i=0;
        //2、关联标识,true-->运行 false -->停止
        while(flag) {
            System.out.println(name+"-->"+i++);
        }
    }
    //3、对外提供方法改变标识
    public void terminate() {
        this.flag = false;
    }
    
    public static void main(String[] args) {
        TerminateThread tt = new TerminateThread("PEPPA");
        new Thread(tt).start();
        
        for(int i = 0;i < 100;i++) {
            if(i == 80) {
                tt.terminate();//线程的终止
                System.out.println("tt game over");
            }
            System.out.println("main-->"+i);
        }
    }

}
复制代码

Thread类中的常用方法

         1.start():启动一个线程,让线程去执行run()

         2.run():线程要执行的具体的内容

         3.currentThread():返回对当前正在执行的线程对象的引用。注意,此方法是静态的,可以直接调用

         4.getName():返回线程的名字

         5.setName():设置线程的名字

         6.isAlive():判断当前线程是否“活着”

         7.sleep(int millious):让当前线程睡眠指定的毫秒数

         8.join():当前线程执行时指定加入另一条线程,直到该加入的线程执行完后,当前线程继续执行

         9.join(int millious):当前线程执行时指定加入另一条线程,无论加入的线程是否执行完,只要指定时间一到,当前线程进入“抢占CPU”状态。

         10.yield():暂停当前正在执行的线程对象,并执行其他线程。

         11.setPriority():设置线程的优先级

         12.getPriority():获得线程的优先级

    注意,设置线程优先级,优先级高的线程并不意味着一定优先获得CPU控制权,而是获得CPU控制权的概率更高。

         ===========

         13.wait(): 让当前线程等待

         14.notify():唤醒正在等待的线程

         15.notifyAll():唤醒正在等待的所有线程

posted @   Tiger-Adan  阅读(1020)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示