一、sleep方法
这个方法使用很多,理解也很简单。让线程处于等待状态(TIME_WAITING),同时不释放资源和锁。示例代码:
public class ThreadTest11 {
public static void main(String[] args) throws Exception {
RunnableThread runnableThread = new RunnableThread(1);
Thread thread1 = new Thread(runnableThread);
Thread thread2 = new Thread(runnableThread);
thread1.start();
Thread.sleep(1000);
thread2.start();
Thread.sleep(1000);
State state1 = thread1.getState(); //线程1等待锁,状态:TIME_WAITING
System.out.println("state1--"+state1);
State state2 = thread2.getState(); //因为线程1调用sleep方法没有释放锁,所以线程2等待锁,状态:BLOCKED
System.out.println("state2--"+state2);
}
}
//输出结果
//state1--TIMED_WAITING
//state2--BLOCKED
public class RunnableThread implements Runnable{
private int number;
public RunnableThread(int number) {
this.number = number;
}
@Override
public void run() {
getLock();
}
private synchronized void getLock() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
二、yield方法
yield方法的作用是:线程放弃自己获得的时间片,然后继续等待CPU的时间片。这句话比较不容易理解。举一个“等公交车”的例子说明一下:
当公交车到站时,会有两种情况;第一:公交车没有位置,没有乘客能够上车,大家继续等下一辆。第二:公交车有位置,乘客可以选择上车和不上车。在第二种情况下,当乘客选择不上车的时候(比如男朋友/女朋友没来,要等他/她一起),就会与其他乘客(没有机会上车)一起等待下一辆公交车。等到下一辆公交车来了,乘客还是可以再选择是否上车,可以无限的循环这个过程。
yield方法的作用就跟上面的例子很类似。 当启动多个线程的之后,多个线程会竞争CPU的资源(时间片)。获得CPU资源(时间片)的线程就会被执行,没有获得CPU资源(时间片)的线程就只能等待,等待CPU分配给他资源(时间片)。而yield方法的作用是:线程放弃自己获得的时间片,然后继续等待CPU的时间片;就像乘客放弃自己上公交车的机会,继续等下一次公交车的情形一样。示例代码:
public class ThreadTest11 {
public static void main(String[] args) throws Exception {
RunnableThread runnableThread = new RunnableThread(1);
Thread thread1 = new Thread(runnableThread);
Thread thread2 = new Thread(runnableThread);
thread1.setPriority(Thread.MIN_PRIORITY); //将thread1的优先权设置为最小值
thread2.setPriority(Thread.MAX_PRIORITY); //将thread2的优先权设置为最大值
thread1.setName("thread1");
thread2.setName("thread2");
thread1.start();
thread2.start();
}
}
public class RunnableThread implements Runnable{
private int number;
public RunnableThread(int number) {
this.number = number;
}
@Override
public void run() {
for(int i=0 ; i<3; i++){ //放大循环次数,效果会更明显
if(Thread.currentThread().getName().equals("thread1")){
Thread.yield(); //调用yield方法,放弃执行权利
}
System.out.println(Thread.currentThread().getName()+" -- "+i);
}
}
}
//输出结果:
/*执行结果的顺序不是固定的,但是可以发现大多数时候都是thread2优先于thread1执行完成
thread2 -- 0
thread2 -- 1
thread2 -- 2
thread1 -- 0
thread1 -- 1
thread1 -- 2
*/
上面的代码主要做了两件事:第一,创建了两个线程,分别赋予最大优先权和最小优先权,并启动。第二,每个循环打印出3以下的整数。当执行线程是thread1时,会调用yield方法。
thread1调用了yield方法,也就是说thread1每打印一个数字之前都会放弃一次它获取到的CPU时间片(但是调用一次yield方法只会放弃一次时间片,当线程再次获得时间片的时候就会继续往下执行,调用yield方法一次是不会放弃两次时间片的),然后跟thread2一起等待下一个时间片。
thread1的优先权是最小值,thread2的优先权是最大值。也就是说在同时竞争CPU时间片的时候,thread2有更大的概率获得时间片(就是当公交车来的时候,thread2有机会上车的概率比thread1大,但是仅仅只是概率大,并不能保证thread2一定比thread1先上车)。
thread2的优先级比thread1高,同时thread1会调用yield方法。因此,执行结果中,thread2应该优先thread1执行(仅仅只是概率,并不一定保证优先)。对比上面的输出结果,也是符合的(可以对比多次执行的输出结果)。
三、join方法
加入调用join方法的线程,并等待调用join方法的线程执行;根据传入的参数不同,等待的时间也不同。分别如下:
1、join(),等待加入的线程执行完成,再继续往下执行。
2、join(2000),等待加入的线程执行,等待时间为2秒,无论加入的线程是否执行完成均继续往下执行
3、join(2000,500000),这个方法与join(2000)的含义是一样的,只是传入的两个参数一个是毫秒(millis)单位,另外一个是纳秒(nanos)单位。
实例代码:
public class ThreadTest12 {
public static void main(String[] args) throws Exception { //这里是main线程
RunnableThread runnableThread = new RunnableThread(1);
Thread thread0 = new Thread(runnableThread);
Thread thread1 = new Thread(runnableThread);
thread0.start();
thread1.start();
System.out.println("线程 : "+Thread.currentThread().getName()+" 执行完成");
}
}
//输出结果
//线程 : main 执行完成 (没有调用join方法,启动线程之后就直接打印出了当前main线程的信息)
//线程 : Thread-1 执行完成
//线程 : Thread-0 执行完成
public class ThreadTest12 {
public static void main(String[] args) throws Exception {
RunnableThread runnableThread = new RunnableThread(1);
Thread thread0 = new Thread(runnableThread);
Thread thread1 = new Thread(runnableThread);
thread0.start();
thread1.start();
thread0.join();
thread1.join();
System.out.println("线程 : "+Thread.currentThread().getName()+" 执行完成");
}
}
//输出结果
//线程 : Thread-0 执行完成
//线程 : Thread-1 执行完成
//线程 : main 执行完成(加入join方法,会等到thread0和thread1执行完成,在往下执行)
public class ThreadTest12 {
public static void main(String[] args) throws Exception {
RunnableThread runnableThread = new RunnableThread(1);
Thread thread0 = new Thread(runnableThread);
Thread thread1 = new Thread(runnableThread);
thread0.start();
thread1.start();
thread0.join(1000); //只等待一秒,无论线程thread0是否执行完均会继续往下执行
thread1.join(1000);
System.out.println("线程 : "+Thread.currentThread().getName()+" 执行完成");
}
}
//输出结果
//线程 : main 执行完成 (调用join方法,只等待一秒。而thread0和thread1执行完成需要2秒的时间)
//线程 : Thread-1 执行完成
//线程 : Thread-0 执行完成
public class RunnableThread implements Runnable{
private int number;
public RunnableThread(int number) {
this.number = number;
}
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(2);
System.out.println("线程 : "+Thread.currentThread().getName()+" 执行完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}