并发编程学习笔记(五、线程中常用的方法)

目录:

  • 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。

原文地址:https://www.cnblogs.com/bzfsdr/p/11568253.html