目录:
- sleep()
- wait()
- notify()/notifyAll()
- yieid()
- join()
- 总结
sleep():
1、sleep()方法的作用是让线程暂停指定的毫秒数。
2、sleep()方法只是暂时交出CPU的执行权,并非释放锁。
3、sleep()方法不需要在synchronize块中执行,而wait()方法需要。
4、sleep()可以通过interrupt()方法打断休眠状态。
5、sleep()只是操作线程,并不涉及线程间的通信。
1 public class SleepTest { 2 /** 3 * sleep()方法不会释放锁,因此线程是按照先后顺序执行的 4 */ 5 public synchronized void sleepMethod() { 6 System.out.println("Sleep start : " + Thread.currentThread().getName()); 7 try { 8 Thread.sleep(1000); 9 } catch (InterruptedException e) { 10 e.printStackTrace(); 11 } 12 System.out.println("Sleep end : " + Thread.currentThread().getName()); 13 } 14 15 /** 16 * wait()方法会释放锁,因此一旦调用wait()方法就会造成其他线程运行 17 */ 18 public synchronized void waitMethod() { 19 System.out.println("Wait start : " + Thread.currentThread().getName()); 20 synchronized (this) { 21 try { 22 wait(1000); 23 } catch (InterruptedException e) { 24 e.printStackTrace(); 25 } 26 } 27 System.out.println("Wait end :" + Thread.currentThread().getName()); 28 } 29 30 public static void main(String[] args) { 31 final SleepTest test1 = new SleepTest(); 32 for (int i = 0; i < 5; i++) { 33 new Thread(test1::sleepMethod).start(); 34 } 35 36 try { 37 //暂停十秒,等上面程序执行完成 38 Thread.sleep(10000); 39 } catch (InterruptedException e) { 40 e.printStackTrace(); 41 } 42 43 System.out.println("-----分割线-----"); 44 45 final SleepTest test2 = new SleepTest(); 46 for (int i = 0; i < 5; i++) { 47 new Thread(test2::waitMethod).start(); 48 } 49 } 50 }
sleep都是一个一个执行完,先start再end,从这一现象便知sleep()方法并不会释放锁;而wait则不会交出CPU的执行权。
若将18、20行的synchronize删除,wait()方法便会抛出IllegalMonitorStateException异常,所以wait()方法必须要在synchronize块或synchronize方法中执行。
wait():
1、wait()、notify()方法通常成对出现。
2、wait()、notify()方法都需要在synchronize块或synchronize方法中执行。
3、wait()方法可以通过interrupt()方法打断暂停状态。
4、通过为wait()方法设置时间(wait(1000))或调用notify()方法可以让对象重新获取锁。
notify()、notifyAll():
1、notify()用来唤醒此对象上等待的单个线程,notifyAll()唤醒多个线程。
2、notifyAll()唤醒的顺序为先进后出(类似于栈),Last In First Out。
3、wait()、notify()、notifyAll()涉及线程间的通信。
1 public class WaitClassDemo { 2 3 private static SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); 4 5 public static void main(String[] args) { 6 Object obj = new Object(); 7 for (int i = 0; i < 5; i++) { 8 new WaitThread(i + "", obj).start(); 9 } 10 new NotifyThread(obj).start(); 11 } 12 13 /** 14 * 调用wait()方法的线程 15 */ 16 static class WaitThread extends Thread { 17 Object obj; 18 public WaitThread(String name, Object obj) { 19 setName("WaitThread" + name); 20 this.obj = obj; 21 } 22 23 @Override 24 public void run() { 25 synchronized (obj) { 26 System.out.println(sdf.format(new Date()) + " " + getName() + " before wait()"); 27 try { 28 obj.wait(); 29 } catch (InterruptedException e) { 30 e.printStackTrace(); 31 } 32 System.out.println(sdf.format(new Date()) + " " + getName() + " after wait()"); 33 } 34 } 35 } 36 37 /** 38 * 调用notify()/notifyAll() 39 */ 40 static class NotifyThread extends Thread { 41 Object obj; 42 public NotifyThread(Object obj) { 43 setName("NotifyThread"); 44 this.obj = obj; 45 } 46 47 @Override 48 public void run() { 49 synchronized (obj) { 50 try { 51 Thread.sleep(5000); 52 } catch (InterruptedException e) { 53 e.printStackTrace(); 54 } 55 System.out.println(sdf.format(new Date()) + " NotifyThread before notify()"); 56 // 唤醒所有线程 用notifyAll()会按照后进先出(LIFO)的原则恢复线程 57 obj.notifyAll(); 58 try { 59 Thread.sleep(5000); 60 } catch (InterruptedException e) { 61 e.printStackTrace(); 62 } 63 System.out.println(sdf.format(new Date()) + " NotifyThread after notify()"); 64 } 65 } 66 } 67 }
yieId():
1、作用:告诉CPU你这次分给我的资源我不要了,你去给其它线程吧( ̄︶ ̄)↗
2、注意:
- yieId()方法不能保证其它线程一定能够执行,因为它仍是可执行状态,所以仍有可能被CPU再次执行。
- 执行yieId()方法不会释放锁。
join():
1、作用:让一个线程在另一个线程执行完后再执行。
2、注意:线程A内部执行线程B的join()方法,那么A将会阻塞,直到线程B执行完后才会执行线程A。
3、Demo:小明点了一个煎饼果子,老板收到订单后便开始做煎饼;那小明肯定是不可能在煎饼果子来之前啥事都不做,老板也一样;所以我们这里用线程来实现他们两个的动作。
1 public class Consumer { 2 3 public void eat() { 4 System.err.println("开始吃煎饼果子..."); 5 try { 6 Thread.sleep(1000); 7 } catch (InterruptedException e) { 8 e.printStackTrace(); 9 } 10 System.err.println("煎饼果子吃完啦..."); 11 } 12 }
1 public class Producer { 2 3 public void manufacture() { 4 System.out.println("开始制作煎饼果子..."); 5 try { 6 Thread.sleep(1000); 7 } catch (InterruptedException e) { 8 e.printStackTrace(); 9 } 10 System.out.println("煎饼果子制作完成..."); 11 } 12 }
1 public class JoinTest { 2 3 public static void main(String[] args) { 4 Thread producerThread = new Thread(() -> { 5 Producer producer = new Producer(); 6 producer.manufacture(); 7 }); 8 producerThread.start(); 9 10 Thread consumerThread = new Thread(() -> { 11 try { 12 producerThread.join(); 13 } catch (InterruptedException e) { 14 e.printStackTrace(); 15 } 16 Consumer consumer = new Consumer(); 17 consumer.eat(); 18 }); 19 consumerThread.start(); 20 } 21 }
总结:
1、方法调用:sleep()、yieId()都是Thread类的静态方法;join()是Thread类的实例方法;wait()、notify()、notifyAll()是Object类的实例方法。
2、释放锁:Thread.sleep()、Thread.yieId()不会释放锁;wait()会释放锁。
3、执行位置:sleep()、yieId()、join()不一定需要在synchronize块中执行;wait()、notify()、notifyAll()需要在synchronize块中执行,否则会抛出IllegalMonitorStateException。