调用thread.start()方法,是让线程处于可运行状态
让线程暂时离开运行状态的三中方法:
1、调用线程的sleep()方法,使线程睡眠一段时间
2、调用线程的yield()方法,使线程暂时回到可运行状态,来使其他线程有机会执行。
3、调用线程的join()方法,使当前线程停止执行,知道当前线程中加入的线程执行完毕后,当前线程才可以执行。
理解 线程的yield()方法: 让一个运行的线程,线程锁,处于可运行状态
1:线程让出处理器资源,让处理器执行其他线程(也包括再次执行当前线程,jvm是随机选择可运行线程的)
2:让线程由运行状态转到可运行状态
3:JVM的调度程序随机选择处于可运行状态的线程来执行,此时可能有两种执行过程:(1)选择一个线程运行,直到此线程阻塞或者运行到死亡。(2)时间分片机制,为线程池中的每个线程都提供均匀的运行机会。
理解 线程的 sleep()方法:让当前运行的线程,处于睡眠,时间过后处于可运行状态,在此期间不释放线程锁
、1线程处于睡眠状态时,JVM调度程序会暂停此线程的执行并来执行其他的处于可运行状态的线程。
2:Thread .sleep() 的作用是使当前执行的线程处于睡眠状态,而不是Thread对象(sleep,是Thread类的静态方法)
理解:线程的join()(非静态方法):让一个线程b 加入到线程A的尾部,等线程A,执行完毕后再继续执行,
1:相当于:一个B方法里在执行A方法,A方法结束后,继续执行B未执行完的代码
2:main线程只等1000毫秒,不管T什么时候结束.
- public class JoinTest implements Runnable{
- public static int a = 0;
- public void run() {
- for (int k = 0; k < 5; k++) {
- a = a + 1;
- }
- }
- public static void main(String[] args) throws Exception {
- Runnable r = new JoinTest();
- Thread t = new Thread(r);
- t.start();
- System.out.println(a);
- }
- }
- public static void main(String[] args) throws Exception {
- Runnable r = new JoinTest();
- Thread t = new Thread(r);
- t.start();
- t.join(); //加入join()
- System.out.println(a);
- }
这个时候,程序输入结果始终为5。
为了证明如果不使用t.join()方法,主线程main方法的System.out.println(a);语句将抢先执行,我们可以在main方法中加入一个循环,这个循环用来延长main方法执行的时间,循环次数将严重取决于机器性能。如果循环次数得当,我们也可以看到a的输出结果是5。
- public static void main(String[] args) throws Exception {
- Runnable r = new JoinTest();
- Thread t = new Thread(r);
- t.start();
- //t.join(); //加入join()
- /*
- 注意循环体内一定要有实际执行语句,否则编译器或JVM可能优化掉你的这段代码,视这段代
- 码为无效。
- */
- for (int i=0; i<300; i++) {
- System.out.print(i);
- }
- System.out.println();
- System.out.println(a);
- }
经自己测试,最后a一直是5.
synchronized (thread),获取线程对象t的锁,并Sleep(9000)后释放,这就意味着,即使
main方法t.join(1000),等待一秒钟,它必须等待ThreadTest 线程释放t锁后才能进入wait方法中,它实际等待时间是9000+1000 MS
其实Join方法实现是通过wait(小提示:Object 提供的方法)。 当main线程调用t.join时候,main线程会获得线程对象t的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main线程,比如退出后。
每个线程都有一个线程栈