一、Thread类中的方法调用方式
学习Thread类中的方法是学习多线程的第一步。在学习多线程之前特别提出一点,调用Thread中的方法的时候,在线程类中,有两种方式,一定要理解这两种方式的区别:
1、this.XXX()
这种调用方式表示的线程是线程实例本身
2、Thread.currentThread.XXX()或Thread.XXX()
上面两种写法是一样的意思。这种调用方式表示的线程是正在执行Thread.currentThread.XXX()所在代码块的线程
当然,这么说,肯定有人不理解两者之间的差别。没有关系,之后会讲清楚,尤其是在讲Thread构造函数这块。讲解后,再回过头来看上面2点,会加深理解。
二、Thread类中的实例方法
从Thread类中的实例方法和类方法的角度讲解Thread中的方法,这种区分的角度也有助于理解多线程中的方法。实例方法,只和实例线程(也就是new出来的线程)本身挂钩,和当前运行的是哪个线程无关。看下Thread类中的实例方法:
1、start()方法
start()方法的作用讲得直白点就是通知"线程规划器",此线程可以运行了,正在等待CPU调用线程对象的run()方法,产生一个异步执行的效果。
举例:
public class Thread01 implements Runnable{ @Override public void run() { for(int i = 0; i < 5; i++) { try { Thread.sleep((int) Math.random() * 5000); System.out.println(Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } } }
public class Test { public static void main(String[] args) { Runnable runnable = new Thread01(); Thread thread = new Thread(runnable); thread.start(); for(int i = 0; i < 5; i++) { try { Thread.sleep((int) Math.random() * 5000); System.out.println(Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } } }
第一次运行结果:
Thread-0 main Thread-0 main Thread-0 main Thread-0 main Thread-0 main
第二次运行结果:
main Thread-0 main Thread-0 main Thread-0 Thread-0 Thread-0 main main
可以看到,CPU调用哪个线程具有不确定性。再举例说明start()方法的顺序是否就是线程启动的顺序?
public class Thread01 implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()); } }
public class Test { public static void main(String[] args) { Runnable runnable = new Thread01(); //创建线程1 Thread thread1 = new Thread(runnable); //创建线程2 Thread thread2 = new Thread(runnable); //创建线程3 Thread thread3 = new Thread(runnable); thread1.start(); thread2.start(); thread3.start(); } }
第一次运行的结果:
Thread-1 Thread-0 Thread-2
第二次运行的结果:
Thread-2 Thread-0 Thread-1
尽管启动线程的顺序是thread1,thread2,thread3,但是被调用的顺序却不是按照启动顺序来的。即:调用start()方法的顺序不代表线程的启动顺序,线程的启动顺序具有不确定性。
2、run()方法
线程开始执行,虚拟机调用的是线程run()方法中的内容,当线程没有通过start()方法让其处于被调用状态的时候,其线程的run()方法不会被执行的。但是如果直接通过.run()来调用的话,还是可以调用的到,但这个时候run()方法所在线程就是主线程了,仅仅只是一个普通方法而已,不在充当线程中的run()方法的作用。
举例:通过.start()方法获取run()方法所在的线程
public class Thread01 implements Runnable{ @Override public void run() { System.out.println("run方法所在的线程为:" + Thread.currentThread().getName()); } }
public class Test { public static void main(String[] args) { Runnable runnable = new Thread01(); //创建线程 Thread thread1 = new Thread(runnable); thread1.start(); } }
结果:
run方法所在的线程为:Thread-0
可以看到run()方法所在的线程就是我们创建的线程,而不再main主线程内。
通过.run()方法获取run()方法所在的线程
public class Thread01 implements Runnable{ @Override public void run() { System.out.println("run方法所在的线程为:" + Thread.currentThread().getName()); } }
public class Test { public static void main(String[] args) { Runnable runnable = new Thread01(); //创建线程 Thread thread1 = new Thread(runnable); thread1.run(); } }
结果:
run方法所在的线程为:main
可以看到,此时run()方法所在的线程就是main主线程,而不再是我们自己创建的那个线程。
所以,通过start()方法启动线程将自动调用 run()方法,这是由jvm的内存机制规定的。不通过start()方法来直接调用的话,run()方法只是thread的一个普通方法,还是在主线程里执行。
参考资料: