线程状态
线程驱动任务(任务在线程中执行)。线程可以是以下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():唤醒正在等待的所有线程
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!