Java多线程(二)线程调度
2022/3/3 22:14:57
本文主要是介绍Java多线程(二)线程调度,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Java多线程(二)
1.线程的生命周期及状态转换
六种状态:
- NEW(新建状态):创建一个线程后,该线程对象就处于新建状态,此时它不能运行,仅仅由JVM为其分配了内存,没有表现出任何线程的动态特征。
- RUNNABLE(可运行状态):新建状态的线程调用start()方法就会进入可运行状态。在RUNNABLE状态又可细分成两种状态:READY(就绪状态)和RUNNING(运行状态),并且线程可以在二者间转换。
- 就绪状态:调用start()方法后等待JVM调度。
- 运行状态:线程对象获得JVM调度,若存在多个CPU,那么允许多个线程并行运行。
- BLOCKED(阻塞状态):处于运行状态的线程可能会因为某些原因失去CPU执行权,暂时停止运行进入阻塞状态。此时JVM不会给线程分配CPU,直到线程重新进入就绪状态,才有机会转换到运行状态。一般以下两种情况会进入阻塞状态:
- 线程A运行中,试图获取同步锁时,却被线程B获取,此时JVM把线程A存到对象的锁池中。
- 线程运行过程中发出I/O请求时,此时该线程也会进入阻塞状态。
- WAITING(等待状态):将运行状态的线程调用了无时间参数限制的方法后,如:wait()、join()等方法,就会将当前运行中的线程转换为等待状态。处于该状态时,必须等其他线程执行特定操作后,才有机会再次争夺CPU使用权,将等待状态的线程转换为运行状态。
- TIMED_WAITING(定时等待状态):将运行状态的线程转换为定时等待状态与转换为等待状态操作类似,只是运行线程调用了有时间参数限制的方法。
- TERMINATED(终止状态):线程的run()方法、call()方法正常执行完毕或线程抛出了一个未捕获的异常、错误,线程就进入终止状态。进入终止状态,线程不在拥有运行资格,也不能转换到其他状态,生命周期结束。
2.线程的调度
线程调度的两种模型:
- 分时调度模型:让所有线程轮流获得CPU使用权。
- 抢占式调度模型:让可运行池中所有就绪状态的线程抢占CPU的使用权,优先级高的线程获得CPU执行权的概率较大。
线程优先级
对线程进行调度,最直接的方法是设置线程优先级,用1~10之间的整数来表示,数字越大优先级越高。也可以使用Thread类的三个静态常量表示线程优先级。
static int MAX_PRIORITY //最高优先级,相当于10 static int MIN_PRIORITY //最低优先级,相当于1 static int NORM_PRIORIY //普通优先级,相当于5
程序运行期间,就绪状态的每个线程都有优先级,如main()具有普通优先级。线程优先级不是固定不变的,可以通过Thread类的setPriority(int newPriority)方法进行设置。
举例:
public class Page364 { public static void main(String[] args) { Thread thread1=new Thread(()->{ for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName()+"正在输出i:"+i); } },"优先级较低的线程"); Thread thread2=new Thread(()->{ for(int j=0;j<10;j++){ System.out.println(Thread.currentThread().getName()+"正在输出j:"+j); } },"优先级较高的线程"); thread1.setPriority(Thread.MIN_PRIORITY); thread2.setPriority(10); thread1.start(); thread2.start(); } }
3.线程休眠
使用静态方法sleep(long millis)方法使线程暂停一段时间,这样其他线程就可以得到执行机会。但该方法会抛出InterruptedException异常,因此调用该方法时应捕获异常或声明抛出异常。
举例:
public class Page365 { public static void main(String[] args) { Thread thread1=new Thread(()->{ for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName()+"正在输出i:"+i); if(i==2){ try{ Thread.sleep(500); }catch(InterruptedException e){ e.printStackTrace(); } } } }); Thread thread2=new Thread(()->{ for(int j=0;j<10;j++){ System.out.println(Thread.currentThread().getName()+"正在输出j:"+j); } }); thread1.start(); thread2.start(); } }
4.线程让步
线程让步可以通过yield()方法来实现,与sleep()有点类似,都可以让正在运行的线程暂停,但yield()不会阻塞该线程,它只是将线程转换成就绪状态,让系统的调度器重新调度一次,,使用yield()后,与当前线程优先级相同或更改的线程可以获得执行机会。
举例:
class YieldThread extends Thread{ public YieldThread(String name){ super(name); } public void run(){ for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName()+"---"+i); if(i==2){ System.out.println("线程让步"); Thread.yield(); } } } } public class Page367 { public static void main(String[] args) { Thread thread1=new YieldThread("thread1"); Thread thread2=new YieldThread("thread2"); thread1.start(); thread2.start(); } }
5.线程插队
Thread类中提供了join()方法,在某个线程中调用其他线程的join()方法时,调用的线程将被堵塞,直到被join()方法加入的线程执行完成之后它才会继续运行。
举例:
class EmergencyThread implements Runnable{ public void run(){ for(int i=1;i<6;i++){ System.out.println(Thread.currentThread().getName()+"输入:"+i); } } } public class Page368 { public static void main(String[] args) throws InterruptedException{ Thread thread1=new Thread(new EmergencyThread(),"thread1"); thread1.start(); for(int i=1;i<6;i++){ System.out.println(Thread.currentThread().getName()+"输入:"+i); if(i==2){ thread1.join(); } } } }
这篇关于Java多线程(二)线程调度的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-07-02springboot项目无法注册到nacos-icode9专业技术文章分享
- 2024-06-26结对编程到底难不难?答案在这里
- 2024-06-19《2023版Java工程师》课程升级公告
- 2024-06-15matplotlib作图不显示3D图,怎么办?
- 2024-06-1503-Loki 日志监控
- 2024-06-1504-让LLM理解知识 -Prompt
- 2024-06-05做软件测试需要懂代码吗?
- 2024-06-0514-ShardingSphere的分布式主键实现
- 2024-06-03为什么以及如何要进行架构设计权衡?
- 2024-05-31全网首发第二弹!软考2024年5月《软件设计师》真题+解析+答案!(11-20题)