* (2) LockSupport类
LockSupport是JUC提供的一个线程阻塞与唤醒的工具类,该工具类可以让线程在任意位置阻塞和唤醒,其所有的方法都是静态方法。
/**
* park()方法练习
*/
public class LockSupportDemo1 {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(()->{
System.out.println("t1线程开始休眠");
//无休止休眠 t1线程为阻塞态 为Waiting
LockSupport.park();
System.out.println("t1线程结束休眠");
});
//启动线程t1
t1.start();
//休眠主线程,让线程t1能顺利执行
TimeUnit.SECONDS.sleep(3);
System.out.println(t1.getState());//Waiting
}
}
/**
* unpark()方法练习
*/
public class LockSupportDemo2 {
public static void main(String[] args) throws InterruptedException {
Thread t2 = new Thread(()->{
System.out.println("t1线程开始休眠");
//休眠指定的时间 休眠后可以在休眠时间段内重新被唤醒 比较灵活
LockSupport.parkNanos(10000000000L);
System.out.println("t1线程结束休眠");
});
//启动线程t2
t2.start();
//休眠主线程,让线程t2能顺利执行
TimeUnit.SECONDS.sleep(3);
LockSupport.unpark(t2);
System.out.println(t2.getState());//Time_Waiting(不定)
System.out.println("线程被唤醒");
System.out.println(t2.getState());//TERMINATED
}
}
当调用park()方法时,会让线程进入WAITING状态,调用parkNanos(long nanos)方法时,线程会进入TIMED_WAITING状态
/**
* unpark()方法练习
*/
public class LockSupportDemo2 {
public static void main(String[] args) throws InterruptedException {
Thread t2 = new Thread(()->{
System.out.println("t1线程开始休眠");
//休眠指定的时间 休眠后可以在休眠时间段内重新被唤醒 比较灵活
LockSupport.parkNanos(10000000000L);
System.out.println("t1线程结束休眠");
});
//启动线程t2
t2.start();
//休眠主线程,让线程t2能顺利执行
TimeUnit.SECONDS.sleep(3);
LockSupport.unpark(t2);
System.out.println(t2.getState());//Time_Waiting(不定)
System.out.println("线程被唤醒");
System.out.println(t2.getState());//TERMINATED
}
}
LockSupport.park()和Thread.sleep()的区别:
1、Thread.sleep()无法从外部唤醒。只能自己醒过来;而被LockSupport.park()方法阻塞的线程可以通过调用LockSupport.unpark()方法去唤醒。
2、被Thread.sleep()、LockSupport.park()方法所阻塞的线程有一个特点,当被阻塞线程的Thread.interrupt()方法调用时,被阻塞线程的中断标志将被设置,该线程将被唤醒。不同的是,二者对中断信号的响应方式不同:LockSuppport.park()方式不会抛出InterruptedExcepton异常,仅仅设置了线程的中断标志;而Thread.sleep()方法会抛出InterruptedException异常
3、与Thread.sleep()相比,调用LockSupport.park()更能精准、更加灵活地阻塞、唤醒指定线程。
2、线程让步
yield()方法是一个和 sleep()方法有点相似的方法,它也是 Thread 类提供的一个静态方法,它也可以让当前正在执行的线程暂停,但它不会阻塞该线程,它只是将该线程转入就绪状态。
yield()只是让当前线程暂停一下,让系统的线程调度器重新调度一次,线程调度器会从线程就绪队列里获取一个线程优先级高的线程,当然完全可能的情况是:当某个线程调用了yield()方法暂停之后,线程调度器又将其调度出来重新执行。
当某个线程调用了yield()方法暂停之后,只有优先级与当前线程相同,或者优先级比当前线程更高的处于就绪状态的线程才会获得执行的机会。下面程序使用yield()方法来让当前正在执行的线程暂停。
/**
* yield()方法练习
*/
public class YieldDemo {
public static void main(String[] args) {
Thread t1 = new Thread(()->{
for (int i = 1; i < 30; i++) {
System.out.println(Thread.currentThread().getName()+"=============="+i);
if(i%10==0){
//调用yield方法让t1线程暂停
Thread.yield();
}
}
},"t1");
Thread t2 = new Thread(()->{
for (int i = 0; i < 30; i++) {
System.out.println(Thread.currentThread().getName()+">>>"+i);
}
},"t2");
//yield之后,有可能原来执行的线程继续获得执行的机会
//为t1线程设置优先级
t1.setPriority(10);
//启动t1线程
t1.start();
//为t2线程设置优先级
t2.setPriority(1);
//启动t2线程
t2.start();
//优先级大的线程不一定先执行,而是执行概率大
for (int i = 0; i < 30; i++) {
System.out.println(Thread.currentThread().getName()+">>>"+i);
}
}
}
sleep()方法和yield()方法的区别:
1. sleep()方法暂停当前线程后,会给其他线程执行机会,不会理会其他线程的优先级;但yield()方法会给优先级相同,或优先级更高的线程执行机会。
2. sleep()方法会将线程转入阻塞状态,直到经过阻塞时间才会转入就绪状态;而yield()不会将线程转入阻塞状态,它只是强制当前线程进入就绪状态。因此完全有可能某个线程调用yield()方法暂停之后,立即再次获得处理器资源被执行。
3. sleep()方法声明抛出了 InterruptedException 异常,所以调用 sleep()方法时要么捕捉该异常,要么显式声明抛出该异常;而yield()方法则没有声明抛出任何异常。