【搞懂Java多线程之二】多线程调度及守护进程

在前一篇文章中说到,所有处在就绪状态中的线程,操作系统会选择优先级最高的优先进行调度,那么是不是优先级高的线程就一定比优先级低的线程先执行呢?线程的优先级又是怎么划分的呢?这篇文章,楼楼就要来说说这个问题啦!欢迎关注我的个人博客主页1.线程的优先级在Java中,线程优先级的范围为0-10,整数值越大,说明优先级更高。几个相关的宏定义:MAX_PRIORITY 10,最高优先级MIN_PRIORITY 1,最低优先级NORM_PRIORITY 5,默认优先级相关的接口setPriority(int x),设置线程的优先级getPriority(),获取线程的优先级既然线程之间有优先级,那是不是优先级高的就一定比优先级低的线程先执行呢?答案是不是的。只能说优先级高的线程有更大的可能性获得CPU,但这并不意味着就一定会先执行。

小伙伴们,我们下面来看一段代码的例子吧,呼呼(~ o ~)~zZ

package net.mindview.util;//第一步、实现Runnable接口class MyThreadRunning implements Runnable{//第二步、重写run方法public void run() {for (int i = 0; i <= 3; i++) {System.out.println(Thread.currentThread().getName());}}}public class MyThread {public static void main(String[] args) {//第三步、实例化自定义的线程类对象MyThreadRunning mtr1 = new MyThreadRunning();MyThreadRunning mtr2 = new MyThreadRunning();MyThreadRunning mtr3 = new MyThreadRunning();//第四步、实例化一个Thread类对象并将自定义的线程类对象作为参数传入,后面一个参数为线程名Thread thread1 = new Thread(mtr1, "Thread 1 is running");Thread thread2 = new Thread(mtr2, "Thread 2 is running");Thread thread3 = new Thread(mtr3, "Thread 3 is running");thread1.setPriority(Thread.MAX_PRIORITY);thread2.setPriority(Thread.MIN_PRIORITY);thread3.setPriority(Thread.NORM_PRIORITY);//第五步、调用start方法启动线程thread1.start();thread2.start();thread3.start();}}运行结果:Thread 1 is runningThread 1 is runningThread 2 is runningThread 1 is runningThread 3 is runningThread 3 is runningThread 3 is runningThread 3 is runningThread 1 is runningThread 2 is runningThread 2 is runningThread 2 is running当当当,小伙伴们是不是明白了呢?优先级高的线程原来并不一定会先执行啊?只是有比较大的可能会获得CPU调度。小伙伴们,可能会问,都设定优先级了,还是不能保证线程按照我所希望的先后顺序去执行,我还有什么招呢?嗯,看完下面的内容,你就能学到一些招了,它就是我们的线程调度。

2.线程调度关于线程调度,我们需要了解,只有良好的调度,才能发挥良好的系统性能,提高程序的执行效率。但是,再怎么好的调度,也都无法精确的控制程序的运行。通常我们采用线程调度的方法主要有sleep,yield和join等方法。下面我们一个一个看哈!sleep()方法,sleep就如英文意思所释,睡眠。当某个程序进入睡眠状态时,,就会将CPU资源交给其他线程,而当休眠时间到时,程序又自动由阻塞状态进入就绪状态,等待CPU资源的调度。sleep()参数是毫秒级的,如sleep(1000)是让线程休眠1s。调用这个方法的时候,需要捕获InterruptedException异常。看下面的代码吧

package net.mindview.util;//第一步、实现Runnable接口class MyThreadRunning implements Runnable{//第二步、重写run方法public void run() {for (int i = 0; i <= 3; i++) {System.out.println(Thread.currentThread().getName());try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}public class MyThread {public static void main(String[] args) {//第三步、实例化自定义的线程类对象MyThreadRunning mtr1 = new MyThreadRunning();MyThreadRunning mtr2 = new MyThreadRunning();MyThreadRunning mtr3 = new MyThreadRunning();//第四步、实例化一个Thread类对象并将自定义的线程类对象作为参数传入,后面一个参数为线程名Thread thread1 = new Thread(mtr1, "Thread 1 is running");Thread thread2 = new Thread(mtr2, "Thread 2 is running");Thread thread3 = new Thread(mtr3, "Thread 3 is running");//第五步、调用start方法启动线程thread1.start();thread2.start();thread3.start();}}运行结果:Thread 2 is runningThread 3 is runningThread 1 is runningThread 3 is runningThread 2 is runningThread 1 is runningThread 2 is runningThread 1 is runningThread 3 is runningThread 3 is runningThread 2 is runningThread 1 is running从运行结果中可以看出,线程无法精确的控制先后顺序。每次运行结果都有可能不一样。

yield方法yield方法也像英文的意思一样,就是让步。暂停当前线程,让出CPU运行时间,进入就绪状态,从而让其他线程获得CPU时间。不过对于抢占式操作系统没有什么意义,或者说没有效果。

package net.mindview.util;//第一步、实现Runnable接口class MyThreadRunning1 implements Runnable{//第二步、重写run方法public void run() {for (int i = 0; i <= 3; i++) {System.out.println(Thread.currentThread().getName());}}}//第一步、实现Runnable接口class MyThreadRunning2 implements Runnable{//第二步、重写run方法public void run() {for (int i = 0; i <= 3; i++) {System.out.println(Thread.currentThread().getName());Thread.yield();}}}public class MyThread {public static void main(String[] args) {//第三步、实例化自定义的线程类对象MyThreadRunning1 mtr1 = new MyThreadRunning1();MyThreadRunning2 mtr2 = new MyThreadRunning2();//第四步、实例化一个Thread类对象并将自定义的线程类对象作为参数传入,后面一个参数为线程名Thread thread1 = new Thread(mtr1, "Thread 1 is running");Thread thread2 = new Thread(mtr2, "Thread 2 is running");//第五步、调用start方法启动线程thread1.start();thread2.start();}}运行效果: 如果不加yield的可能的运行结果:Thread 1 is running Thread 1 is runningThread 2 is running Thread 2 is runningThread 1 is running Thread 1 is runningThread 2 is running Thread 1 is runningThread 1 is running Thread 1 is runningThread 2 is running Thread 2 is runningThread 1 is running Thread 2 is runningThread 2 is running Thread 2 is running从运行效果中可以看出,线程2每执行一次就会让出CPU资源一次,但也只是可能的运行结果。

join方法join方法的作用可能从英文意思上理解不是那么简单,那其实呢,join方法的作用是想让一个线程等待另一个线程执行完毕后再继续执行。可以添加参数,long类型的毫秒,等待该进程终止最长为多少秒。如thread.mt()就是等thread线程执行完之后,再执行其他的程序。我们可以看下面的代码:package net.mindview.util;//第一步、继承Thread类class MyThreadRunning extends Thread{//构造函数public MyThreadRunning() {super("My Thread");}//第二步、重写run方法public void run() {for (int i = 0; i <= 3; i++) {System.out.println("新建一个线程" + getName()+i);try {sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}public class MyThread {public static void main(String[] args) {//第三步、实例化自定义的线程类对象MyThreadRunning mtr = new MyThreadRunning();//第四步、调用start方法从而启动run方法mtr.start();try {mtr.join();} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("mtr你执行完了是吧?我是主线程,我要来打印了。");}}运行结果:新建一个线程My Thread0新建一个线程My Thread1新建一个线程My Thread2新建一个线程My Thread3mtr你执行完了是吧?我是主线程,我要来打印了。3.守护进程守护进程也叫后台进程,是一种为其他线程提供服务的一种线程。当虚拟机检测到没有用户进程执行了的话,即使还有后台进程,JVM也有可能会退出的。相关接口:setDaemon(boolean)将一个线程设置为后台进程;Thread.isDaemon()判断一个线程是否为后台进程。我们可以来看下面的代码:package net.mindview.util;//第一步、继承Thread类public class MyThread {public static void main(String[] args) {Thread t1 = new MyCommon();Thread t2 = new Thread(new MyDaemon());t2.setDaemon(true);//设置为守护线程t2.start();t1.start();} } class MyCommon extends Thread {public void run() {for (int i = 0; i < 5; i++) {System.out.println("线程1第" + i + "次执行!");try {Thread.sleep(7);} catch (InterruptedException e) {e.printStackTrace();}}} } class MyDaemon implements Runnable {public void run() {for (long i = 0; i < 9999999L; i++) {System.out.println("后台线程第" + i + "次执行!");try {Thread.sleep(7);} catch (InterruptedException e) {e.printStackTrace();}}} }运行结果:线程1第0次执行!后台线程第0次执行!后台线程第1次执行!线程1第1次执行!线程1第2次执行!后台线程第2次执行!线程1第3次执行!后台线程第3次执行!线程1第4次执行!后台线程第4次执行!后台线程第5次执行!同学们,由运行结果中是不是可以看出,后台线程还没有执行完呢,程序就退出了。以上就是我们关于Java多线程的第二部分内容了,总结一下,这篇文章主要讲Java多线程的调度问题。调度方法主要有睡眠啊,让步啊,以及join啊之类的。但是要清楚,无论程序员怎么进行调度,也都无法实现线程的精确控制。当时良好的线程调度可以提高程序运行的效率。最后我们讲到守护线程,也就是后台线程,这里需要注意的事,虚拟机检测到没有用户线程运行了的话,不管有没有后台线程,都会退出。嗯,就这么多了,小伙伴们,都掌握了吗?下面一篇文章,我们要学习的是经典问题,生产者和消费者之类的线程同步问题,加油加油加油,未完待续哦~~~

接受失败等于放松自己高压的心理,

【搞懂Java多线程之二】多线程调度及守护进程

相关文章:

你感兴趣的文章:

标签云: