05_多线程

来源:互联网 发布:php 表单验证 数据库 编辑:程序博客网 时间:2024/05/16 18:53

一、多线程简介

(1)、进程:是一个正在执行中的程序

             每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或者叫一个控制单元

(2)、线程:就是进程中一个独立的控制单元

             线程在控制着进程的执行。

            一个进程中至少要有一个线程

           开启多个线程是为了同时运行多部分代码

           每一个线程都有自己运行的内容,这个内容可以称为线程要执行的任务

           线程运行的程序在main方法中,该线程就是主线程。

(3)、多线程的利与弊:

多线程的好处:解决了多部分同时运行的问题

多线程的弊端:线程太多回到的效率降低

(4)、多线程的随机性:

其实应用程序的执行都是cpu在做着快速的切换完成的 ,这个切换是随机的,我们可以形象把多线程的运行行为在互相抢夺cpu执行权。这就是多线程的随机性。

jvm启动时就启动了多个线程,至少有两个线程可以分析出来

1、执行main函数的线程

该线程的任务代码都定义在main函数中

2、负责垃圾回收的线程

二、线程的创建

(1)、方式一: 继承Thread类

步骤:

1、定义类继承Thread.

2、复写Thread类中的run方法。

      目的:将自定义代码存储在run方法。让线程运行。

3、调用线程的start方法。

      该方法有两个作用 :启动线程,调用run方法。


为什么要覆盖run方法呢?

      Thread类用于描述线程。

      该类就定义了一个功能,用于存储线程要运行的代码,该存储功能就是run方法。

      也即是说run方法是用于存储线程要运行的代码。

[java] view plain copy
  1. public class Demo {  
  2.     public static void main(String[] args) {  
  3.         /* 
  4.          * 创建线程的目的就是为了开启一条执行路径,去运行的代码和其他代码实现同时运行 
  5.          *  
  6.          * 而运行的代码就是这个执行路径的任务 
  7.          *  
  8.          * jvm创建的主线程的任务都定义在了主函数中。 
  9.          *  
  10.          * 而自定义的线程它的任务在哪呢? Thread类用于描述线程,线程是需要任务的,所以Thread类也对任务的描述 
  11.          * 这个任务就是通过Thread类的run方法来体现的, 也就是说,run方法封装自定义线程运行任务的函数 
  12.          *  
  13.          * run方法中定义就是线程要运行的任务代码 
  14.          *  
  15.          * 开启线程就是运行指定代码,所以只有继承Thread类,并复写run方法。 将运行的代码定义在run方法中即可 
  16.          */  
  17.         Demo4 d4 = new Demo4("李四");  
  18.         Demo4 d5 = new Demo4("张三");  
  19.         //<strong><span style="color:#ff0000;"> d4.run();//仅仅是对象调用方法。而线程创建了,并没有执行</span></strong>  
  20.         <span style="color:#ff0000;">d4.start();// 开启线程调用run方法</span>  
  21.         d5.start();  
  22.         System.out.println("结束了这个线程。。" + Thread.currentThread().getName());  
  23.     }  
  24. }  
  25.   
  26. /** 
  27.  * 继承方式 
  28.  */  
  29. class Demo4 extends Thread {  
  30.     private String name;  
  31.   
  32.     Demo4(String name) {  
  33.         <span style="color:#ff0000;">super(name);// 给定义的线程命名</span>  
  34.     }  
  35.   
  36.     // 重写run方法  
  37.     public void run() {  
  38.         // 循环测试  
  39.         for (int x = 0; x < 10; x++) {  
  40.             System.out.println(name + ".." + x + "..."  
  41.                     + Thread.currentThread().getName());  
  42.         }  
  43.     }  
  44. }  

新建状态(New):新创建了一个线程对象。

就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。

没有执行资格的情况下是冻结状态。sleep(), 时间到 wait(),notify()

有执行资格的状态叫做临时状态。

既有资格又有执行权运行状态。

死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。


线程对象以及名称:

原来线程都有自己默认的名称。

Thread-编号 该编号从0开始。

Thread 对象的setName() getName();方法

线程初始化名称:

构造方法 super(name);

Thread currentThread():获取当前正在执行的线程对象的引用。

(2)、方式二:实现Runnable接口

        1、步骤:

 a、定义类实现Runnable接口

 b、覆盖接口Runnable中的run方法,将线程的任务代码封装到run方法中

 c、通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递

        为什么呢?因为线程的任务都封装在Runnable接口子类对象的run方法中。 所以要线程对象的start方法开启线程

d、调用Thread类中的start方法,开启线程并调用Runnnable接口。

        2、实现Runnable接口的好处:

 a、将线程的任务从线程的子类中分离出来,进行单独的封装

       按照面向对象的思想将任务封装成对象

b、避免了java单继承的局限性

      所以创建线程的第二种方式较为常用

[java] view plain copy
  1. public class Test9 {  
  2.     public static void main(String[] args) {  
  3.         TextThread t = new TextThread();  
  4.         Thread t1 = new Thread(t);//线程1  
  5.         Thread t2 = new Thread(t);//线程2  
  6.         t1.start();  
  7.         t2.start();  
  8.     }  
  9. }  
  10. /** 
  11.  * 继承方式,实现Runnable接口 
  12.  * @author Administrator 
  13.  * 
  14.  */  
  15. class TextThread implements Runnable {  
  16.  //重写run方法  
  17.     @Override  
  18.     public void run() {  
  19.         // TODO Auto-generated method stub  
  20.         show();  
  21.     }  
  22.     //测试方法  
  23.     public void show() {  
  24.         for (int i = 0; i < 20; i++) {  
  25.             System.out.println(Thread.currentThread().getName() + "..." + i);  
  26.   
  27.         }  
  28.     }  
  29.   
  30. }  
(3)、两者的区别:

继承Thread:线程代码存放在Thread子类run方法中

实现Runnnable:线程代码存在接口子类的run方法。

在定义线程时,建议使用实现方式。

三、线程的安全问题

(1)、发现问题

[java] view plain copy
  1. public class Test9 {  
  2.     public static void main(String[] args) {  
  3.         Ticket1 t = new Ticket1();  
  4.         // 开启四个线程  
  5.         Thread t1 = new Thread(t);  
  6.         Thread t2 = new Thread(t);  
  7.         Thread t3 = new Thread(t);  
  8.         Thread t4 = new Thread(t);  
  9.   
  10.         t1.start();  
  11.         t2.start();  
  12.         t3.start();  
  13.         t4.start();  
  14.     }  
  15. }  
  16.   
  17. class Ticket1 implements Runnable {  
  18.     private int ticket = 10;// 共享数据  
  19.   
  20.     public void run() {  
  21.         while (ticket > 0) {  
  22.             if (ticket > 0) {  
  23.                 try {  
  24.                     Thread.sleep(10);  
  25.                 } catch (InterruptedException e) {  
  26.                     e.printStackTrace();  
  27.                 }  
  28.                 System.out.println(Thread.currentThread().getName() + "。。sale。。"  
  29.                         + ticket--);// 有负数的存在,安全隐患  
  30.             }  
  31.         }  
  32.     }  
  33. }  

通过分析,发现,打印出0,-1,-2等错票

1、问题原因:

      当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。

      导致共享数据的错我。

(2)、解决办法:

对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。

Java对于多线程的安全问题提供了专业的解决方式。

这种专业的解决方式就是:同步代码快

 哪些代码需要同步,就看哪些语句在操作共享数据。

synchronized(对象){

需要被同步的代码

}

程序示例:

[java] view plain copy
  1. public class Test9 {  
  2.     public static void main(String[] args) {  
  3.         //开启4个线程  
  4.         Ticket1 t = new Ticket1();  
  5.         Thread t1 = new Thread(t);  
  6.         Thread t2 = new Thread(t);  
  7.         Thread t3 = new Thread(t);  
  8.         Thread t4 = new Thread(t);  
  9.         t1.start();  
  10.         t2.start();  
  11.         t3.start();  
  12.         t4.start();  
  13.     }  
  14. }  
  15.   
  16. class Ticket1 implements Runnable {  
  17.     private int ticket = 100;  
  18.   
  19.     Object obj=new Object();  
  20.     public void run() {  
  21.   
  22.         while (true) {  
  23.         //同步代码块,加锁,对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。  
  24.             synchronized (this) {  
  25.                 if (ticket > 0) {  
  26.                     try {  
  27.                         Thread.sleep(10);//让线程休眠  
  28.                     } catch (Exception e) {  
  29.                         e.printStackTrace();  
  30.                     }  
  31.                     System.out.println(Thread.currentThread().getName()  
  32.                             + "。。sale。。" + ticket--);//没有出现负数票  
  33.                 }  
  34.             }  
  35.         }  
  36.     }  
  37. }  

1、同步代码快的理解:

        对象如同锁,持有锁的线程可以在同步中执行。

        没有持有锁的线程即使获取cpu的执行权,也进不去,因为没有获取锁。

        举例:火车上的卫生间,里面有人时,门就会锁住,别人就进不去。只有人出来了,把门打开,其他人才能进去。

2、同步的前提:

      a、必须要有两个或者两个以上的线程。

      b、必须是多个线程使用同一个锁。

            必须保证同步中只能有一个线程在运行。

3、同步的利与弊:

       好处:解决多线程的安全问题。

       弊端:多个线程需要判断锁,较为消耗资源。允许消耗范围内的。

(3)、同步的两种表现形式

1、是同步代码块(如上程序段所示)

2、是同步函数。把synchronized作为修饰符放在函数上。

程序示例:


[java] view plain copy
  1. public class Test10 {  
  2.     public static void main(String[] args) {  
  3.         Tickets t = new Tickets();  
  4.         // 创建4个线程卖票,并开启  
  5.         Thread t1 = new Thread(t);  
  6.         Thread t2 = new Thread(t);  
  7.         Thread t3 = new Thread(t);  
  8.         Thread t4 = new Thread(t);  
  9.         t1.start();  
  10.         t2.start();  
  11.         t3.start();  
  12.         t4.start();  
  13.     }  
  14. }  
  15.   
  16. class Tickets implements Runnable {  
  17.     private int ticket = 1000;// 票数  
  18.   
  19.     // 复写run方法调用show  
  20.     public void run() {  
  21.         while (ticket > 0) {  
  22.             this.show();  
  23.         }  
  24.     }  
  25.   
  26.     // 同步函数所持有的锁是this  
  27.     public synchronized void show() {  
  28.         if (ticket > 0) {  
  29.             try {  
  30.                 Thread.sleep(10);  
  31.             } catch (InterruptedException e) {  
  32.                 e.printStackTrace();  
  33.             }  
  34.             System.out.println(Thread.currentThread().getName() + "...sale..."  
  35.                     + ticket--);  
  36.         }  
  37.     }  
  38. }  

(4)、同步函数和同步代码块:

       1、同步函数使用的锁是this

验证:使用两个线程来买票。

一个线程在同步代码块中。

一个线程在同步函数中。

都在执行买票动作。

       2、同步代码块使用的锁是任意对象。

(5)、静态同步函数的锁

静态的同步函数使用的锁是:该函数所属字节码文件对象

可以使用getClass方法获取,也可以用“当前类名.class“表示

静态的同步方法使用的锁是该方法所在类的字节码对象。

验证方法如下:

[java] view plain copy
  1. public class Test10 {  
  2.     public static void main(String[] args) {  
  3.         Tickets t = new Tickets();  
  4.         // 创建4个线程卖票,并开启  
  5.         Thread t1 = new Thread(t);  
  6.         Thread t2 = new Thread(t);  
  7.         /* 
  8.          * Thread t3=new Thread(t); Thread t4=new Thread(t); 
  9.          */  
  10.         t1.start();// t1一开启跑到同步代码块中。,开启这个线程不一定立即执行。处于临时状态,有可能执行下面一句  
  11.         t.flag = false;// 在t2开启之前,把标识变为false;  
  12.         try {  
  13.             Thread.sleep(10);// 主线程停止10毫秒,只能是t1在运行。过了时间段,可能执行下面的语句  
  14.         } catch (InterruptedException e) {  
  15.             // TODO Auto-generated catch block  
  16.             e.printStackTrace();  
  17.         }  
  18.         t2.start();// t2一开启跑到同步函数中。  
  19.         /* 
  20.          * t3.start(); t4.start(); 
  21.          */  
  22.     }  
  23. }  
  24.   
  25. class Tickets implements Runnable {  
  26.     private static int tick = 1000;// 票数  
  27.     // 复写run方法调用show  
  28.     Object obj = new Object();  
  29.     boolean flag = true;  
  30.   
  31.     @Override  
  32.     public void run() {  
  33.         // TODO Auto-generated method stub  
  34.         if (flag) {  
  35.             while (true) {  
  36.                 // 同步代码块  
  37.                 // synchronized(obj),存在安全问题  
  38.                 synchronized (Test10.class) {  
  39.                     if (tick > 0) {  
  40.                         try {  
  41.                             Thread.sleep(10);  
  42.                             System.out.println("同步代码块");  
  43.                         } catch (InterruptedException e) {  
  44.                             // TODO Auto-generated catch block  
  45.                             e.printStackTrace();  
  46.                         }  
  47.                     }  
  48.                 }  
  49.             }  
  50.         } else {  
  51.             while (true) {  
  52.                 show();  
  53.             }  
  54.         }  
  55.     }  
  56.   
  57.     // 同步函数  
  58.     public synchronized void show() {  
  59.         if (tick > 0) {  
  60.             try {  
  61.                 Thread.sleep(10);  
  62.                 System.out.println("同步函数");  
  63.             } catch (InterruptedException e) {  
  64.                 // TODO Auto-generated catch block  
  65.                 e.printStackTrace();  
  66.             }  
  67.         }  
  68.     }  
  69. }  

(6)、懒汉式单利模式:

加入同步为了解决线程安全问题

加入双重判断是为了解决效率问题

此处是懒汉式示例:

[java] view plain copy
  1. public class Test10 {  
  2.     public static void main(String[] args) {  
  3.         System.out.println("hello");  
  4.     }  
  5. }  
  6.   
  7. class SingleDemo {  
  8.     private static SingleDemo s = null;// 共享数据,多个线程并发访问getInstance(),有可能存在安全问题,多条语句操作  
  9.   
  10.     private SingleDemo() {// 私有构造函数  
  11.     }  
  12.   
  13.     public static SingleDemo getInstance() {  
  14.         if (s == null) {  
  15.             synchronized (SingleDemo.class) {// 锁是字节码文件对象  
  16.                 if (s == null) {  
  17.                     s = new SingleDemo();// 对象延迟加载  
  18.                 }  
  19.             }  
  20.         }  
  21.         return s;  
  22.     }  
  23. }  

(7)、线程死锁

两个对象互相依赖,所以死锁!示例代码如下:

[java] view plain copy
  1. public class Test10 implements Runnable {  
  2.     public int flag = 1;  
  3.     static Object o1 = new Object(), o2 = new Object();//两个锁  
  4.     public void run() {  
  5.         System.out.println("flag=" + flag);  
  6.         //两个锁相持不下  
  7.         if (flag == 1) {  
  8.             synchronized (o1) {  
  9.                 try {  
  10.                     Thread.sleep(500);  
  11.                 } catch (Exception e) {  
  12.                     e.printStackTrace();  
  13.                 }  
  14.                 synchronized (o2) {  
  15.                     System.out.println("1");  
  16.                 }  
  17.             }  
  18.         }  
  19.         if (flag == 0) {  
  20.             synchronized (o2) {  
  21.                 try {  
  22.                     Thread.sleep(500);  
  23.                 } catch (Exception e) {  
  24.                     e.printStackTrace();  
  25.                 }  
  26.                 synchronized (o1) {  
  27.                     System.out.println("0");  
  28.                 }  
  29.             }  
  30.         }  
  31.     }  
  32.   
  33.     public static void main(String[] args) {  
  34.         Test10 td1 = new Test10();  
  35.         Test10 td2 = new Test10();  
  36.         //定义标识  
  37.         td1.flag = 1;  
  38.         td2.flag = 0;  
  39.         //两个线程开启  
  40.         Thread t1 = new Thread(td1);  
  41.         Thread t2 = new Thread(td2);  
  42.         t1.start();  
  43.         t2.start();  
  44.     }  
  45. }  

四、线程间的通讯

(1)、概述:其实就是多个线程在操作同一个资源,但是操作的动作不同

程序示例:

[java] view plain copy
  1. class Res {  
  2.     String name;  
  3.     String sex;  
  4.     boolean flag = false;// 标记是否有 资源  
  5. }  
  6.   
  7. // 添加类,实现Runnable接口  
  8. class Input implements Runnable {  
  9.     private Res r;// 资源对象  
  10.   
  11.     public Input(Res r) {// 关联资源对象  
  12.         this.r = r;  
  13.     }  
  14.   
  15.     // 重写run方法  
  16.     public void run() {  
  17.         // TODO Auto-generated method stub  
  18.         int x = 0;// 这里也必须要加线程,操作共享数据,同一个锁,可以是资源对象  
  19.         while (true) {  
  20.             synchronized (r) {  
  21.                 if (r.flag) {  
  22.                     try {  
  23.                         r.wait();// 等待  
  24.                     } catch (InterruptedException e) {  
  25.                         // TODO Auto-generated catch block  
  26.                         e.printStackTrace();  
  27.                     }  
  28.                 }  
  29.                 if (x == 0) {  
  30.                     r.name = "丽丽";  
  31.                     r.sex = "女";  
  32.                 } else {  
  33.                     r.name = "mike";  
  34.                     r.sex = "man";// 线程结束后,有可能还能抢到cpu执行权  
  35.                 }  
  36.                 x = (x + 1) % 2;  
  37.                 r.flag = true;  
  38.                 r.notify();// 唤醒线程池中的最早wait的线程。  
  39.             }  
  40.         }  
  41.     }  
  42. }  
  43.   
  44. // 输出类实现Runnable接口  
  45. class Output implements Runnable {  
  46.     private Res r;  
  47.   
  48.     public Output(Res r) {// 关联资源对象  
  49.         this.r = r;  
  50.     }  
  51.   
  52.     // 重写run方法  
  53.     public void run() {  
  54.         // TODO Auto-generated method stub  
  55.         while (true) {  
  56.             synchronized (r) {  
  57.                 if (!r.flag) {  
  58.                     try {  
  59.                         r.wait();// 等待,取消了执行资格  
  60.                     } catch (InterruptedException e) {  
  61.                         // TODO Auto-generated catch block  
  62.                         e.printStackTrace();  
  63.                     }  
  64.                 }  
  65.                 System.out.println(r.name + "..." + r.sex);  
  66.                 r.flag = false;  
  67.                 r.notify();// 叫醒线程池中的最早线程  
  68.             }  
  69.         }  
  70.     }  
  71. }  
  72.   
  73. public class Test {  
  74.     public static void main(String[] args) {  
  75.         Res r = new Res();  
  76.         // 形象的比喻 有一堆煤,有两个大卡车,一个进的,一个出的,把煤放到大卡车上,把卡车放到高速公路上。  
  77.         Input in = new Input(r);  
  78.         Output out = new Output(r);  
  79.         // 开启两个线程  
  80.         Thread t1 = new Thread(in);  
  81.         Thread t2 = new Thread(out);  
  82.         t1.start();  
  83.         t2.start();  
  84.     }  
  85. }  

(2)、分析问题:

a、以上的代码还是有问题的,按理说应该是存一个打印一个这样是比较靠谱的。上面的情况是一大片一大片的男,或者女。为什么出现这种情况?

输入的线程如果获得了cpu执行权,它存了一个值后,其他线程进不来,这个时候出了同步,output,input都有可能抢到cpu执行权。所以输入有可能还会抢到,前面的值就回被覆盖掉了。当某一时刻,执行权被抢走了,输出被抢到了,他也可能把一个值打印多遍,所以造成了上面的情况。cpu切换造成的。现在需求是这样的,添加一个,取出一个,这样才是最靠谱的。为了满足条件需求,我们要做的是,在资源中加入一个标记,默认false;输入线程在往里面添加数据时,判断标记,false则存入,存完后,输入线程可能还持有执行权,将标记改为真,代表里面有数据了。为true时,不能在存入了,这个时候,让输入线程等着不动,wait()放弃了执行资格;当取走了之后,才能醒,notify()。

当output具备执行权的时候,开始输出,之前也要进行判断,如果true,取出,打印,变为false还持有执行权,回来之后,为false,wati(),叫醒 input,input等的时候,再把output叫醒。等待唤醒机制。

wait();

notity();

notityAll();

都是用在同步中。因为要对持有监视器(锁)的线程操作。

所以要使用同步中,因为只有同步才具有锁。


b、为什么这些操作线程的方法要定义在Object中呢?

因为这些方法在操作同步线程时,都必须要标识它们所操作线程只有的锁。

只有同一个锁上的被等待线程,可以被同一个锁上notity唤醒。

也就是说,等待和唤醒必须是同一个锁。

而锁可以是任意对象,所以可以被任意对象调用的方法定义在Object类中。

优化后的代码:

[java] view plain copy
  1. class Res {  
  2.     private String name;  
  3.     private String sex;  
  4.     boolean flag = false;  
  5.     //设置添加方法  
  6.     public synchronized void set(String name, String sex) {  
  7.         if (flag) {  
  8.             try {  
  9.                 this.wait();//线程等待,没有执行资格  
  10.             } catch (InterruptedException e) {  
  11.                 // TODO Auto-generated catch block  
  12.                 e.printStackTrace();  
  13.             }  
  14.         }  
  15.         this.name = name;  
  16.         this.sex = sex;  
  17.         flag = true;//有了数据,标识变为true;  
  18.         this.notify();//唤醒线程池中的最早wait的线程  
  19.     }  
  20.      //输出方法  
  21.     public synchronized void out() {  
  22.         if (!flag) {  
  23.             try {  
  24.                 this.wait();//线程等待,没有执行资格  
  25.             } catch (InterruptedException e) {  
  26.                 // TODO Auto-generated catch block  
  27.                 e.printStackTrace();  
  28.             }  
  29.         }  
  30.         System.out.println(name + ".." + sex);//打印  
  31.         flag = false;//取走了数据,变为false;  
  32.         this.notify();//唤醒线程池中的最早wait的线程  
  33.     }  
  34. }  
  35. //添加类,input  
  36. class Input implements Runnable {  
  37.     private Res r;  
  38.   
  39.     public Input(Res r) {//关联资源  
  40.         this.r = r;  
  41.     }  
  42.     //重写run方法  
  43.     public void run() {  
  44.         // TODO Auto-generated method stub  
  45.         int x = 0;  
  46.         while (true) {  
  47.   
  48.             if (x == 0) {  
  49.                 r.set("mike""man");  
  50.             } else {  
  51.                 r.set("丽丽""女");  
  52.             }  
  53.             x = (x + 1) % 2;  
  54.   
  55.         }  
  56.     }  
  57.   
  58. }  
  59. //输出类  
  60. class Output implements Runnable {  
  61.     private Res r;  
  62.   
  63.     public Output(Res r) {//关联资源  
  64.         this.r = r;  
  65.     }  
  66.   
  67.     public void run() {  
  68.         // TODO Auto-generated method stub  
  69.         while (true) {  
  70.   
  71.             r.out();  
  72.         }  
  73.     }  
  74. }  
  75.   
  76. public class Test {  
  77.     public static void main(String[] args) {  
  78.         Res r = new Res();//资源对象  
  79.         //创建两个线程,并开启  
  80.         new Thread(new Input(r)).start();  
  81.         new Thread(new Output(r)).start();  
  82.   
  83.     }  
  84. }  

五、Lock接口

解决线程安全问题使用同步的形式,(同步代码块,要么同步函数)其实最终使用的都是锁机制。

到了后期版本,直接将锁封装成了对象。线程进入同步就是具备了锁,执行完,离开同步,就是释放了锁。

在后期对锁的分析过程中,发现,获取锁,或者释放锁的动作应该是锁这个事物更清楚。所以将这些动作定义在了锁当中,并把锁定义成对象。

所以同步是隐示的锁操作,而Lock对象是显示的锁操作,它的出现就替代了同步。

在之前的版本中使用Object类中wait、notify、notifyAll的方式来完成的。那是因为同步中的锁是任意对象,所以操作锁的等待唤醒的方法都定义在Object类中。

而现在锁是指定对象Lock。所以查找等待唤醒机制方式需要通过Lock接口来完成。而Lock接口中并没有直接操作等待唤醒的方法,而是将这些方式又单独封装到了一个对象中。

这个对象就是Condition,将Object中的三个方法进行单独的封装。并提供了功能一致的方法 await()、signal()、signalAll()体现新版本对象的好处。

< java.util.concurrent.locks > Condition接口:await()、signal()、signalAll();

成功的 lock 操作与成功的 Lock 操作具有同样的内存同步效应。

成功的 unlock 操作与成功的 Unlock 操作具有同样的内存同步效应

原创粉丝点击