1. sleep()
-
sleep()是Thread中的静态本地方法。
public static native void sleep(long millis) throws InterruptedException;
-
sleep方法是让线程进入阻塞队列,cpu不会分配时间片给
阻塞
中的线程,可以使用该特性,防止cpu空转。public static void main (String[] args) { Thread t1 = new Thread(() -> { while (true){ //Thread.sleep(5); //如果不使用sleep, 轮到该线程执行时会一直空转,占用资源 } }); t1.start(); }
-
调用sleep方法后,线程处于TIME_WAITING状态。
-
阻塞状态:
线程状态处于BLOCKED、WAITING 、TIME_WAITING这三种统称为堵塞状态。
public static void main (String[] args) throws Exception { Thread t1 = new Thread(() -> { try { Thread.sleep(5000); //阻塞5秒 } catch (InterruptedException e) { e.printStackTrace(); } }); t1.start(); System.out.println("sleep前的状态:" + t1.getState()); Thread.sleep(1000); System.out.println("sleep后的状态:" + t1.getState()); }
sleep前的状态:RUNNABLE sleep后的状态:TIMED_WAITING
2. yield()
- yield()是Thread中的静态本地方法。
public static native void yield();
- yield方法是让出cpu给同等级或者优先级更高的线程,使线程进入等待队列,可以重新竞争线程锁。
- 调用yield方法后,线程处于 RUNNABLE状态。
执行结果:线程2输出的值比线程1小很多,所以线程1获取cpu的时间片比线程2多public static void main (String[] args) { Thread t1 = new Thread(() -> { int count = 0; for (; ;) { System.out.println("线程1执行:" + count++); } }); Thread t2 = new Thread(() -> { int count = 0; for (; ;) { Thread.yield(); //让出cpu给其他线程 System.out.println("------------线程2执行:" + count++); } }); t1.start(); t2.start(); }
线程1执行:62243 线程1执行:62244 ------------线程2执行:25428 线程1执行:62245 线程1执行:62246 线程1执行:62247
3. interrupt()、isInterrupted()、interrupted()
-
interrupt()是Thread中的普通方法,需要通过对象调用,表示将调用的线程中断状态置为true
-
isInterrupted()方法也是Thread中的普通方法,interrupted()是Thread中的静态方法,两个底层都是调用的同一个静态本地方法,两者都是返回当前线程的中断状态,区别是interrupted()会清除中断标记,isInterrupted()不会清除中断标记,ClearInterrupted为true表示清除,false表示不清除。
-
如果线程是处于
阻塞
状态,例如sleep、wait、join等,线程会立即退出阻塞状态,并且抛出InterruptedException异常,便于后续程序继续处理。public static void main (String[] args) { Thread t = new Thread(() -> { try { Thread.sleep(5000); } catch (InterruptedException e) { System.out.println("如果阻塞状态被打断,可以catch异常,并且做处理"); } System.out.println("继续执行代码"); //被打断后会执行这段代码 }); t.start(); //开启多线程 //Thread.sleep(1000); t.interrupt(); //打断t3的状态 }
-
如果线程是正常执行状态,会将线程的中断标志从false设置为true,程序继续执行,不受影响,线程中可以获取到线程的执行状态。
public static void main (String[] args) { Thread t = new Thread(() -> { while (true) { //死循环 //获取线程的中断状态,如果为true代表被中断 if (Thread.interrupted()) { System.out.println("线程被中断了"); break; } } System.out.println("继续执行代码"); }); t.start(); //开启多线程 //Thread.sleep(1000); t.interrupt(); //打断t3的状态 }
4. join()
- Thread中的方法,作用是让当前线程挂起,等待其他线程结束后再往下执行,通常用于主线程中,等待子线程调用结束后再执行主线程。
public static void main (String[] args) { Thread t1 = new Thread(() -> { for (int j = 0; j < 5; j++) { //Thread.sleep(50); //让线程阻塞50ms System.out.println("t1"); } }); t1.start(); /* 主线程中调用t1.join(),那就是主线程调用的wait()方法,主线程进入等待队列,持有的锁是t1, 当t1线程结束后,释放锁,调用notifyAll(),主线程获取锁,再继续执行 */ t1.join(); //主线程调用t1.join()后,会等待t1线程结束后,才会执行主线程 for (int j = 0; j < 5; j++) { //Thread.sleep(50); //让线程阻塞50ms System.out.println("main"); }
- join()方法内部其实调用的是wait方法,这里产生一个问题,当子线程调用结束后,怎么通知主线程呢,因为代码中并没有显示调用
notify()
或者notifyAll()
方法,所以这里涉及到一个知识点:当线程执行完run方法后,会自动执行notifyAll()方法,释放持有的锁。
5. wait()
- wait()是Object中的方法,Object中wait提供三种方法
//第一种:静态本地方法,timeout必须大于等于0,否则报:timeout value is negative //当timeout等于0时,线程必须由其他线程唤醒才能重新获取锁 //当timeout大于0时,线程最多等待指定的时间之后,继续往下执行 public final native void wait(long timeout) throws InterruptedException; //第二种:直接调用(调用的静态本地方法,参数为0) public final void wait() throws InterruptedException { wait(0); //参数为0,当前线程必须由其他线程唤醒 } //第三种,带有两个参数,底层还是调用的是第一种静态本地方法, //如果传入的timeout为0,但是nanos大于0时, public final void wait(long timeout, int nanos) throws InterruptedException { if (timeout < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (nanos < 0 || nanos > 999999) { throw new IllegalArgumentException("nanosecond timeout value out of range"); } if (nanos > 0) { timeout++; } wait(timeout); //调用的还是静态本地方法 }
6. notify()、notifyAll()
- 两个都是Object中的方法,其中notify()会随机唤醒一个等待获取该对象锁的线程(由调度器决定),而notifyAll()会唤醒所有等待获取该对象锁的线程。