- 谦让yield()
- yield() 定义在Thread.java中,而不是Object中。
- 作用:
- 让步。它能让当前线程由 “运行状态”—>“就绪状态”,从而让其它具有相同优先级的等待线程获取执行权;但是,并不能保证在当前线程调用yield()之后,其它具有相同优先级的线程就一定能获得执行权;也有可能是当前线程又进入到“运行状态”继续运行!
- 和sleep类似,让线程从“运行状态”到“就绪状态”,但是不会阻塞线程,只是让当前线程停一会儿,让同优先级的其他线程获得被执行的机会,但是不保证一定会被执行。
- 源码:
- 这是一个静态方法,本地方法。一旦执行,它会使当前线程让出CPU。但要注意,让出CPU不代表它不执行了。虽然让出CPU,它还会进行CPU资源的争夺,但是能否被再次分配到就不一定了。
- 因此,yield()的寓意就是:我已经完成了一些最重要的工作了,我可以休息一下了。
- yield()示例
package com.wwj.text;
public class WaitTest{
public static void main(String[] args){
Thread t1 = new ThreadA("t1");
Thread t2 = new ThreadA("t2");
t1.start();
t2.start();
}
}
class ThreadA extends Thread{
public ThreadA(String name){
super(name);
}
@Override
public synchronized void run() {
for(int i=0 ; i<5 ;i++){
System.out.print(this.getName()+"["+this.getPriority()+"]"+":"+i+" ");
if(i % 4 == 0){
Thread.yield();
}
}
}
}
- 结果:
t1[5]:0 t2[5]:0 t1[5]:1 t2[5]:1 t1[5]:2 t2[5]:2 t1[5]:3 t2[5]:3 t1[5]:4 t2[5]:4
- “线程t1”在能被4整数的时候,并没有切换到“线程t2”。这表明,yield()虽然可以让线程由“运行状态”进入到“就绪状态”;但是,它不一定会让其它线程获取CPU执行权(即,其它线程进入到“运行状态”),即使这个“其它线程”与当前调用yield()的线程具有相同的优先级。
- 等待线程结束join()
- join() 定义在Thread.java中,而不是Object中
- join()也是“加入”的意思,也就是一个线程要加入另外一个线程,最好的方法就是等着它(另外一个线程执行完)一起走。
- 作用: 让 “主线程”等待“子线程”结束之后 才能继续运行。
- 具体来讲:一个线程的输入可能非常依赖于另外一个或者多个线程的输出,此时,这个线程就需要等待依赖线程执行完毕,才能继续执行。
- 两个join()方法:
public final void join() throws InterruptedException { join(0);}
- 代表无限等待,类似wait(),它会一直阻塞当前进程,直到目标进程执行完毕
public final synchronized void join(final long millis) thows InterruptedException{}
- 给了一个最大等待时间,类似于有参数的wait( long millis),超时则不等待
- join()示例:
package com.wwj.text;
public class JoinMain {
public volatile static int i=0;
public static class AddThread extends Thread{
@Override
public void run() {
for(i=0 ; i<10000000 ; i++);
}
}
public static void main(String[] args) throws InterruptedException{
Thread at = new AddThread();
at.start();
at.join();
System.out.println(i);
}
}
- 结果:
10000000
, 如果去除at.join();
,结果为0
- 说明如果不使用join()方法等待AddThread,那么得到的i可能是0或者很小,因为AddThread还没开始执行,i的值就已经被输出了。但是使用join()方法后,表示 主线程愿意等待AddThread执行完毕,跟着AddThread一起往前走,因此在join()使用后,AddThread已经执行完成,因此i总是10000000
- 一个很困惑的点:执行join()的线程为目的线程,是要等这个线程执行完即可
- 进一步说明join()的用法:让“主线程”线程等待“子线程”运行完之后再运行。
//子线程
public class son extends Thread(){
void run(){
......
}
}
//主线程
public class F() extends Thread{
void run(){
son s = new son();
s.start();
s.join();
...
}
}
- 在主线程中调用子线程s.start()启动子线程并调用s.join(),在调用s.join()之后主线程(F)会一直等待,直到子线程(son)运行完毕之后才接着运行。
- join()源码分析:
- 注意的是:类似wait()、notify()方法不要在Thread对象实例上进行使用,因此很可能影响系统API的工作,或者被系统API影响。
- sleep()、wait()、notify()、yield()、join()有什么相同不同点?
- wait()、notify() 是一对,当然这5个都可以单用。
- sleep()、join()、yield()属于Thread.java,wait()、notify()属于Object.java
- wait()让线程从“运行状态”到“阻塞状态”,yield让线程从“运行状态”到“就绪状态”
- wait()和notify()的使用要和“synchronized”内使用,这也是它们属于Object的理由
- wait()会释放同步锁,sleep()不会释放占用资源,yield()释放占用资源,但是同样也会继续争抢。
- yield() 与 wait()的比较
- 我们知道,wait()的作用是让当前线程由“运行状态”进入“等待(阻塞)状态”的同时,也会释放同步锁。
- 而yield()的作用是让步,它也会让当前线程离开“运行状态”。它们的区别是:
- wait()是让线程由“运行状态”进入到“等待(阻塞)状态”,而yield()是让线程由“运行状态”进入到“就绪状态”。
- wait()是会线程释放它所持有对象的同步锁,而yield()方法不会释放锁。