zoukankan      html  css  js  c++  java
  • 《day15---多线程安全问题_JDK1.5的锁机制》

     1 //15同步问题的分析案例以及解决思路
     2 
     3 //两个客户到一个银行去存钱,每个客户一次存100,存3次。
     4 //问题,该程序是否有安全问题,如果有,写出分析过程,并定于解决方案。
     5 
     6 /*
     7 发现运行结果:
     8 sum=200
     9 sum=200
    10 sum=300
    11 sum=400
    12 sum=600
    13 sum=500
    14 
    15 打印错乱,不关心,但是发现数值错误,没有100.
    16 运行了几次,发现有对的。
    17 
    18 
    19 
    20 说明多线程的随机性造成了安全问题。
    21 哪的问题?
    22 1,既然是多线程的问题,必须问题发生在多线程中
    23 2,任务代码中是否有共性数据呢?b对象中的sum.
    24 3,是否有对sum进行多次运算呢?有!
    25 
    26 加同步就行了。
    27 */
    28 //描述银行,
    29 class Bank
    30 {
    31     private int sum;
    32     private Object obj = new Object();
    33     public void add(int num)
    34     {
    35         synchronized(obj)
    36         {
    37             sum = sum+num;
    38             System.out.println("sum="+sum);//每存一次,看到银行金额变化。
    39         }
    40     }
    41 }
    42 
    43 class Consumer implements Runnable
    44 {
    45     private Bank b = new Bank();
    46     public void run()
    47     {
    48         for(int x=0;x<3;x++)
    49         {
    50             b.add(100);//一次存100,循环3次。
    51         }
    52     }
    53 }
    54 class ThreadTest
    55 {
    56     public static void main(String[] args) 
    57     {
    58         Consumer c = new Consumer();
    59         Thread t1 = new Thread(c);
    60         Thread t2 = new Thread(c);
    61         t1.start();
    62         t2.start();
    63     }
    64 }
     1 //同步函数相关问题,以及同步函数和同步代码块的比较
     2 /*
     3 同步的另一种体现形式。同步函数。
     4 
     5 同步函数使用的锁是哪个?
     6 经过简单的分析:大概猜的是this。因为函数必须被对象调用。
     7 
     8 验证:
     9 写一个同步代码块,写一个同步函数。如果同步代码块中的锁对象和同步函数中的锁对象
    10 是同一个,就同步了,就没有错误的数据了,如果不是同一个锁对象,就不同步,会出现错误数据,
    11 
    12 让两个线程,一个线程在同步代码块中执行,一个线程待同步函数中执行。
    13 
    14 总结:同步函数使用的锁是this.
    15 
    16 同步函数和同步代码块的的区别?
    17 1,同步函数使用的锁是固定的this。当线程任务只需要一个同步时,完全可以通过同步函数来体现。
    18 2,同步代码块使用的是锁可以是任意对象。当线程任务需要多个同步时,必须通过所来区分。这时必须使用同步代码块。
    19 同步代码块较为常用。
    20 
    21 如果只用一个同步时,完全可以简化为
    22 */
    23 
    24 class Ticket implements Runnable
    25 {
    26     //1,描述票的数量
    27     private int tickets = 100;
    28 
    29     //2,售票的动作。这个动作需要被多线程执行,那就是线程任务代码,
    30     //需要定义在run方法中。
    31     //记住,线程任务中通常都有循环结构。
    32     //private Object obj = new Object();
    33     boolean flag = true;
    34     public void run()
    35     {
    36         if(flag){
    37         while(true)
    38             {
    39                 synchronized(this)
    40                 {
    41                     if(tickets > 0)
    42                     {
    43                         try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/}
    44                         System.out.println(Thread.currentThread().getName()+"..obj.."+tickets--);//打印线程名称
    45                     }
    46                 }
    47             }
    48         }
    49         
    50         else{
    51             while(true)
    52             {
    53                 this.sale();
    54             }
    55         }
    56     }
    57 
    58     public synchronized void sale()//同步函数。具备了同步性的函数,使用的锁对象就是this
    59     {
    60         if(tickets > 0)
    61         {
    62             //要让线程在这里稍停,模拟问题的发生。sleep 看到了 0 -1 -2 这样的错误的数据,这就是传说中的安全问题。
    63             try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/}
    64             System.out.println(Thread.currentThread().getName()+"..sale.."+tickets--);//打印线程名称
    65         }
    66     }
    67 }
    68 
    69 
    70 class ThreadDemo4
    71 {
    72     public void main(String[] args) 
    73     {
    74         //1,创建Runnable接口的子类对象。
    75         Ticket t = new Ticket();
    76 
    77         //创建四个线程对象。并将Runnable接口的子类对象作为参数传递给Thread的构造函数。
    78         Thread t1 = new Thread(t);
    79         Thread t2 = new Thread(t);
    80 
    81         //3,开启四个线程
    82         t1.start();
    83         
    84         try{Thread.sleep(10);}catch(InterruptedException e){}
    85         //切换标记;之前,让主线程停一会儿,这时就只有一个t1线程在。
    86         t.flag = false;
    87 
    88         t2.start();
    89     }
    90 }
     1 /*
     2 静态同步函数使用的锁不是this.而是字节码文件对象。类名.class
     3 */
     4 
     5 class Ticket implements Runnable
     6 {
     7     //1,描述票的数量
     8     private static int tickets = 100;
     9 
    10     //2,售票的动作。这个动作需要被多线程执行,那就是线程任务代码,
    11     //需要定义在run方法中。
    12     //记住,线程任务中通常都有循环结构。
    13     //private Object obj = new Object();
    14     boolean flag = true;
    15     public void run()
    16     {
    17         if(flag){
    18         while(true)
    19             {
    20                 synchronized(Ticket.class)
    21                 {
    22                     if(tickets > 0)
    23                     {
    24                         try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/}
    25                         System.out.println(Thread.currentThread().getName()+"..obj.."+tickets--);//打印线程名称
    26                     }
    27                 }
    28             }
    29         }
    30         
    31         else{
    32             while(true)
    33             {
    34                 this.sale();
    35             }
    36         }
    37     }
    38 
    39     public static synchronized void sale()//加了静态后,已经知道静态函数里面没有了this.
    40     {
    41         if(tickets > 0)
    42         {
    43             //要让线程在这里稍停,模拟问题的发生。sleep 看到了 0 -1 -2 这样的错误的数据,这就是传说中的安全问题。
    44             try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/}
    45             System.out.println(Thread.currentThread().getName()+"..sale.."+tickets--);//打印线程名称
    46         }
    47     }
    48 }
    49 
    50 
    51 class ThreadDemo5
    52 {
    53     public static void main(String[] args) 
    54     {
    55         //1,创建Runnable接口的子类对象。
    56         Ticket t = new Ticket();
    57 
    58         //创建四个线程对象。并将Runnable接口的子类对象作为参数传递给Thread的构造函数。
    59         Thread t1 = new Thread(t);
    60         Thread t2 = new Thread(t);
    61 
    62         //3,开启四个线程
    63         t1.start();
    64         
    65         try{Thread.sleep(10);}catch(InterruptedException e){}
    66         //切换标记;之前,让主线程停一会儿,这时就只有一个t1线程在。
    67         t.flag = false;
    68 
    69         t2.start();
    70     }
    71 }
     1 //单例懒汉模式的并发访问相关问题
     2 /*
     3 单例懒汉模式的并发访问相关问题
     4 */
     5 
     6 //饿汉式;多线程并发没问题。
     7 class Single
     8 {
     9     private static final Single s = new Single();
    10 
    11     private Single(){}
    12 
    13     public static Single getInstance()
    14     {
    15         return s;
    16     }
    17 }
    18 
    19 //懒汉式:
    20 class Single
    21 {
    22     private static  Single s = null;
    23 
    24     private Single(){}
    25     /*
    26     并发访问,会有安全隐患,所以加入同步机制解决安全问题。
    27     但是,同步的出现却降低了效率。(提稿效率的办法就是减少判断锁的次数)
    28     可以通过双重判断的方式,解决效率问题,减少判断的次数。
    29 
    30     */
    31     public static /*synchronized*/ Single getInstance()
    32     {
    33         if(s==null)//只要有一个线程把对象创建完,其他线程就再也不会判断锁了。
    34         {
    35             synchronized(Single.class)
    36             {
    37                 if(s==null)
    38         //            --->0  --->1
    39                     s = new Single();
    40             }
    41         }
    42         return s;
    43     }
    44 }
    45 class Demo implements Runnable
    46 {
    47     public void run()
    48     {
    49         Single.getInstance();
    50     }
    51 }
    52 
    53 class ThreadDemo6 
    54 {
    55     public static void main(String[] args) 
    56     {
    57         System.out.println("Hello World!");
    58     }
    59 }
      1 //同步的另一个弊端。死锁
      2 /*
      3 同步的另一个弊端。
      4 
      5 情况之一:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。
      6 这时容易引发一种现象,死锁。
      7 这种情况能避免就避免。
      8 
      9 //Thread-0
     10 synchronized(obj1)
     11 {
     12     --->thread-0 obj1
     13     synchronized(obj2)
     14     {
     15 
     16     }
     17 }
     18 
     19 //Thread-1
     20 synchronized(obj2)
     21 {
     22     thread-1 obj2
     23     synchronized(obj1)
     24     {
     25 
     26     }
     27 }
     28 
     29 */
     30 
     31 class Ticket implements Runnable
     32 {
     33     //1,描述票的数量
     34     private int tickets = 100;
     35 
     36     //2,售票的动作。这个动作需要被多线程执行,那就是线程任务代码,
     37     //需要定义在run方法中。
     38     //记住,线程任务中通常都有循环结构。
     39     private Object obj = new Object();
     40     boolean flag = true;
     41     public void run()
     42     {
     43         if(flag){
     44         while(true)
     45             {
     46                 synchronized(obj)//obj锁
     47                 {
     48                     sale();//this锁
     49                 }
     50             }
     51         }
     52         
     53         else{
     54             while(true)
     55             {
     56                 this.sale();
     57             }
     58         }
     59     }
     60 
     61     public  synchronized void sale()//this锁
     62     {
     63         synchronized(obj)//obj锁
     64         {
     65         if(tickets > 0)
     66             {
     67                 //要让线程在这里稍停,模拟问题的发生。sleep 看到了 0 -1 -2 这样的错误的数据,这就是传说中的安全问题。
     68                 try{Thread.sleep(1);}catch(InterruptedException e){/*未写处理方式,后面讲*/}
     69                 System.out.println(Thread.currentThread().getName()+"..sale.."+tickets--);//打印线程名称
     70             }
     71         }
     72     }
     73 }
     74 
     75 
     76 class ThreadDemo7
     77 {
     78     public static void main(String[] args) 
     79     {
     80         //1,创建Runnable接口的子类对象。
     81         Ticket t = new Ticket();
     82 
     83         //创建四个线程对象。并将Runnable接口的子类对象作为参数传递给Thread的构造函数。
     84         Thread t1 = new Thread(t);
     85         Thread t2 = new Thread(t);
     86 
     87         //3,开启四个线程
     88         t1.start();
     89         
     90         try{Thread.sleep(10);}catch(InterruptedException e){}
     91         //切换标记;之前,让主线程停一会儿,这时就只有一个t1线程在。
     92         t.flag = false;
     93 
     94         t2.start();
     95     }
     96 }
     97 
     98 //这个程序在运行过程中死锁了。
     99 /*
    100 Thread-0..sale..100
    101 Thread-0..sale..99
    102 Thread-0..sale..98
    103 Thread-0..sale..97
    104 Thread-0..sale..96
    105 Thread-0..sale..95
    106 */
     1 //死锁示例--面试会用到
     2 class Test implements Runnable
     3 {
     4     private boolean flag;
     5     Test(boolean flag)
     6     {
     7         this.flag = flag;
     8     }
     9     public void run()
    10     {
    11         if(flag)
    12         {
    13             while(true)
    14             {
    15                 synchronized(MyLock.LOCKA)
    16                 {
    17                     System.out.println(Thread.currentThread().getName()+"if......locka");
    18                     synchronized(MyLock.LOCKB)
    19                     {
    20                         System.out.println(Thread.currentThread().getName()+"if......lockb");
    21                     }
    22                 }
    23             }
    24         }
    25         else
    26         {
    27             while(true)
    28             {
    29                 synchronized(MyLock.LOCKB)
    30                 {
    31                     System.out.println(Thread.currentThread().getName()+"else......lockb");
    32                     synchronized(MyLock.LOCKA)
    33                     {
    34                         System.out.println(Thread.currentThread().getName()+"else......locka");
    35                     }
    36                 }
    37             }
    38         }
    39     }
    40 }
    41 
    42 //单独定义一个用于存储锁对象类。
    43 class MyLock
    44 {
    45     public static final Object LOCKA = new Object();
    46     public static final Object LOCKB = new Object();
    47 }
    48 class DeadLockTest
    49 {
    50     public static void main(String[] args) 
    51     {
    52         //创建了两个线程任务。
    53         Test t1 = new Test(true);
    54         Test t2 = new Test(false);
    55 
    56         Thread t11 = new Thread(t1);
    57         Thread t22 = new Thread(t2);
    58         t11.start();
    59         t22.start();
    60     }
    61 }
      1 //多线程间的通信-生产者&消费者-问题发生。
      2 /*
      3 多线程中最为常见的应用案例,
      4 生产者消费者问题。
      5 生产和消费同时执行,需要多线程。
      6 但是执行的任务却不相同,处理的资源是相同的。线程间的通信。
      7 
      8 1,描述资源。
      9 2,描述生产者,因为具备着自己的任务。
     10 3,描述消费者,因为具备着自己的任务。
     11 
     12 问题1:
     13 数据错误,已经被生产很早期的商品,才被消费到。
     14 出现线程安全问题,需要用同步来解决。
     15 问题已解决:不会再消费到之前很早期的商品。
     16 
     17 问题2:
     18 发现了连续生产却没有消费,同时对同一个商品进行多次消费。
     19 希望的结果应该是生产一个商品,就被消费掉,生产下一个商品。
     20 
     21 搞清楚机个问题:
     22 生产者什么时候应该生产呢?
     23 当盘子中没有面包,就生产,如果有了面包,就不要消费。
     24 
     25 消费者什么时候应该消费呢?
     26 当盘子中已有面包,就消费,如果没有面包,就不要消费。
     27 
     28 */
     29 
     30 //1,描述资源。属性:名称和编号。    行为:对商品名称赋值,获取商品
     31 class Resource
     32 {
     33     private String name;
     34     private int count=1;
     35 
     36     //1,提供设置的方法。
     37     public synchronized void set(String name)
     38     {
     39         //1,给成员变量赋值并加上编号。
     40         this.name = name+count;
     41         count++;
     42 
     43         //2,打印生产了哪个商品。
     44         System.out.println(Thread.currentThread().getName()+"....生产者..."+this.name);
     45 
     46     }
     47 
     48     public synchronized void out()
     49     {
     50         System.out.println(Thread.currentThread().getName()+"....消费者..."+this.name);
     51     }
     52 }
     53 
     54 //2,描述生产者。
     55 class Producer implements Runnable
     56 {
     57     private Resource r ;
     58     //生产者一初始化就要有资源。需要将资源传递到构造函数中。
     59     Producer(Resource r)
     60     {
     61         this.r = r;
     62     }
     63     public void run()
     64     {
     65         while(true)
     66         {
     67             r.set("面包");
     68         }
     69     }
     70 }
     71 
     72 //3,描述消费者。
     73 class Consumer implements Runnable
     74 {
     75     private Resource r ;
     76     //消费者一初始化就要有资源。需要将资源传递到构造函数中。
     77     Consumer(Resource r)
     78     {
     79         this.r = r;
     80     }
     81     public void run()
     82     {
     83         while(true)
     84         {
     85             r.out();
     86         }
     87     }
     88 }
     89 
     90 class ThreadDemo8
     91 {
     92     public static void main(String[] args) 
     93     {
     94         //创建资源对象。
     95         Resource r = new Resource();
     96 
     97         //创建线程任务。
     98         Producer pro = new Producer(r);
     99         Consumer con = new Consumer(r);
    100 
    101         //3,创建线程。
    102         Thread t1 = new Thread(pro);
    103         Thread t2 = new Thread(con);
    104 
    105         t1.start();
    106         t2.start();
    107     }
    108 }
      1 //多线程间的通信-生产者&消费者-问题发生。以及等待唤醒机制。
      2 /*
      3 多线程中最为常见的应用案例,
      4 生产者消费者问题。
      5 生产和消费同时执行,需要多线程。
      6 但是执行的任务却不相同,处理的资源是相同的。线程间的通信。
      7 
      8 1,描述资源。
      9 2,描述生产者,因为具备着自己的任务。
     10 3,描述消费者,因为具备着自己的任务。
     11 
     12 问题1:
     13 数据错误,已经被生产很早期的商品,才被消费到。
     14 出现线程安全问题,需要用同步来解决。
     15 问题已解决:不会再消费到之前很早期的商品。
     16 
     17 问题2:
     18 发现了连续生产却没有消费,同时对同一个商品进行多次消费。
     19 希望的结果应该是生产一个商品,就被消费掉,生产下一个商品。
     20 
     21 搞清楚机个问题:
     22 生产者什么时候应该生产呢?
     23 当盘子中没有面包,就生产,如果有了面包,就不要消费。
     24 
     25 消费者什么时候应该消费呢?
     26 当盘子中已有面包,就消费,如果没有面包,就不要消费。
     27 
     28 生产者生产了商品后,应该去告诉消费者来消费。而这时的生产者应该处于等待状态。
     29 消费者消费了商品后,应该告诉生产者去生产,而这时的消费者应该处于等待状态。
     30 
     31 
     32 ======================================================
     33 等待/唤醒机制。
     34 wait();会让线程处于等待状态,其实就是将线程临时存储到了线程池中。
     35 notify();会唤醒线程池中任意一个等待的线程。
     36 notifyAll();会唤醒线程池中所有的等待线程。
     37 
     38 记住:这些方法必须使用在同步中,必须要标识wait,notify等方法所属的锁。
     39 同一个锁上的notify,只能唤醒该锁上的wait线程。
     40 
     41 为什么这些方法定义在了Object中呢?
     42 因为这些方法必须标识所属的锁。而锁可以是任意对象,任意对象可以调用的方法必然是Objec的方法。
     43 
     44 
     45 距离:小朋友抓人游戏。
     46 */
     47 
     48 //1,描述资源。属性:名称和编号。    行为:对商品名称赋值,获取商品
     49 class Resource
     50 {
     51     private String name;
     52     private int count=1;
     53 
     54     //定义标记。
     55     private boolean flag = false;
     56 
     57     //1,提供设置的方法。
     58     public synchronized void set(String name)
     59     {
     60         if(flag)
     61             try{this.wait();}catch(InterruptedException e){}
     62         //1,给成员变量赋值并加上编号。
     63         this.name = name+count;
     64         count++;
     65 
     66         //2,打印生产了哪个商品。
     67         System.out.println(Thread.currentThread().getName()+"....生产者..."+this.name);
     68         
     69         //将标记该为true
     70         flag = true;
     71         //唤醒消费者。
     72         this.notify();
     73 
     74     }
     75 
     76     public synchronized void out()
     77     {
     78         if(!flag)
     79             try{wait();}catch(InterruptedException e){}
     80         System.out.println(Thread.currentThread().getName()+"....消费者..."+this.name);
     81         //将标记该为flase。
     82         flag = false;
     83         //唤醒生产者。
     84         notify();
     85     }
     86 }
     87 
     88 //2,描述生产者。
     89 class Producer implements Runnable
     90 {
     91     private Resource r ;
     92     //生产者一初始化就要有资源。需要将资源传递到构造函数中。
     93     Producer(Resource r)
     94     {
     95         this.r = r;
     96     }
     97     public void run()
     98     {
     99         while(true)
    100         {
    101             r.set("面包");
    102         }
    103     }
    104 }
    105 
    106 //3,描述消费者。
    107 class Consumer implements Runnable
    108 {
    109     private Resource r ;
    110     //消费者一初始化就要有资源。需要将资源传递到构造函数中。
    111     Consumer(Resource r)
    112     {
    113         this.r = r;
    114     }
    115     public void run()
    116     {
    117         while(true)
    118         {
    119             r.out();
    120         }
    121     }
    122 }
    123 
    124 class ThreadDemo9
    125 {
    126     public static void main(String[] args) 
    127     {
    128         //创建资源对象。
    129         Resource r = new Resource();
    130 
    131         //创建线程任务。
    132         Producer pro = new Producer(r);
    133         Consumer con = new Consumer(r);
    134 
    135         //3,创建线程。
    136         Thread t1 = new Thread(pro);
    137         Thread t2 = new Thread(con);
    138 
    139         t1.start();
    140         t2.start();
    141     }
    142 }
      1 //多生产&多消费问题发生及解决。
      2 /*
      3 java.util.concurrent.locks 软件包中提供了相应的解决方案。
      4 Lock接口。比同步更厉害,有更多的操作,获取锁:lock(); 释放锁:unlock();
      5           提供了一个更加面向对象的锁。在该锁中提供了更多的显示的锁操作。
      6           可以替代同步。
      7 
      8 升级到JDK1.5,先别同步改为Lock.
      9 */
     10 
     11 /*
     12 多生产多消费。
     13 问题1:生产了商品没有被消费,同一个商品被消费多次。
     14 Thread-2....生产者...面包285
     15 Thread-0....生产者...面包286
     16 Thread-1....消费者...面包286
     17 Thread-2....生产者...面包287
     18 Thread-0....生产者...面包288
     19 Thread-1....消费者...面包288
     20 
     21 被唤醒的线程没有判断标记,造成了问题1的产生。
     22 解决:只要让被唤醒的线程必须判断标记就可以了。将if判断标记的方式改为while判断标记。
     23 注意:只要是多生产,多消费,必须是while判断标记。
     24 
     25 问题2:while判断后,死锁了。
     26 原因:生产方唤醒了线程池中的生产方的线程。本方唤醒了本方。
     27 解决:希望本方要唤醒对方。没有对应方法,只能唤醒所有。
     28 
     29 其实还是有一些问题的。效率低了。
     30 */
     31 //1,描述资源。属性:名称和编号。    行为:对商品名称赋值,获取商品
     32 class Resource
     33 {
     34     private String name;
     35     private int count=1;
     36 
     37     //定义一个锁对象。
     38     private Lock lock = new ReentrantLock();
     39 
     40     //定义标记。
     41     private boolean flag = false;
     42 
     43     //1,提供设置的方法。
     44     public synchronized void set(String name)// t1 t2
     45     {
     46         //if(flag)
     47         while(flag)
     48             try{this.wait();}catch(InterruptedException e){}
     49         //1,给成员变量赋值并加上编号。
     50         this.name = name+count;//商品1
     51         count++;//2
     52         //2,打印生产了哪个商品。
     53         System.out.println(Thread.currentThread().getName()+"....生产者..."+this.name);//生产了商品1
     54         
     55         //将标记该为true
     56         flag = true;
     57         //唤醒消费者。
     58         this.notifyAll();
     59 
     60     }
     61 
     62     public synchronized void out()// t3 t4
     63     {
     64         //if(!flag)
     65         while(!flag)
     66             try{wait();}catch(InterruptedException e){}
     67         System.out.println(Thread.currentThread().getName()+"....消费者..."+this.name);
     68         //将标记该为flase。
     69         flag = false;
     70         //唤醒生产者。
     71         this.notifyAll();
     72     }
     73 }
     74 
     75 //2,描述生产者。
     76 class Producer implements Runnable
     77 {
     78     private Resource r ;
     79     //生产者一初始化就要有资源。需要将资源传递到构造函数中。
     80     Producer(Resource r)
     81     {
     82         this.r = r;
     83     }
     84     public void run()
     85     {
     86         while(true)
     87         {
     88             r.set("面包");
     89         }
     90     }
     91 }
     92 
     93 //3,描述消费者。
     94 class Consumer implements Runnable
     95 {
     96     private Resource r ;
     97     //消费者一初始化就要有资源。需要将资源传递到构造函数中。
     98     Consumer(Resource r)
     99     {
    100         this.r = r;
    101     }
    102     public void run()
    103     {
    104         while(true)
    105         {
    106             r.out();
    107         }
    108     }
    109 }
    110 
    111 class ThreadDemo10
    112 {
    113     public static void main(String[] args) 
    114     {
    115         //创建资源对象。
    116         Resource r = new Resource();
    117 
    118         //创建线程任务。
    119         Producer pro = new Producer(r);
    120         Consumer con = new Consumer(r);
    121 
    122         //3,创建线程。
    123         Thread t1 = new Thread(pro);
    124         Thread t2 = new Thread(pro);
    125         Thread t3 = new Thread(con);
    126         Thread t4 = new Thread(con);
    127 
    128         t1.start();
    129         t2.start();
    130         t3.start();
    131         t4.start();
    132     }
    133 }
      1 //多生产&多消费问题发生及解决。
      2 import java.util.concurrent.locks.*;
      3 /*
      4 java.util.concurrent.locks 软件包中提供了相应的解决方案。
      5 Lock接口。比同步更厉害,有更多的操作,获取锁:lock(); 释放锁:unlock();
      6           提供了一个更加面向对象的锁。在该锁中提供了更多的显示的锁操作。
      7           可以替代同步。
      8 
      9 升级到JDK1.5,先别同步改为Lock.
     10 已经将旧锁替换成新锁,那么所上的监视器方法(wait notify notifyAll )也应该替换
     11 成新锁上的方法。
     12 而JDK1.5中将这些原有的监视器方法封装到了一个Condition对象中。
     13 想要获取监视器方法,需要先获取Condition对象。
     14 
     15 Condition对象的出现其实就是替代了Object中的监视器方法。
     16 await();
     17 signal();
     18 signalAll();
     19 将所有的监视器方法替换成了Condition.
     20 功能和ThreadDemo10.java的程序一样,仅仅是用新的对象,改了写法而已。
     21 但是问题依旧,效率还是很低。
     22 老程序中可以通过两个嵌套完成,但是容易引发死锁。
     23 
     24 新程序中,就可以解决这个问题。
     25 可以在一个锁上加上多个监视器对象。
     26 */
     27 class Resource
     28 {
     29     private String name;
     30     private int count=1;
     31 
     32     //定义一个锁对象。
     33     private Lock lock = new ReentrantLock();
     34     //获取锁上的Condition对象。为了解决本方唤醒对方的问题,可以一个锁上创建两个监视器对象。
     35     private Condition produce = lock.newCondition();//负责生产的.
     36     private Condition consume = lock.newCondition();//负责消费的.
     37 
     38 
     39     //定义标记。
     40     private boolean flag = false;
     41 
     42     //1,提供设置的方法。
     43     public void set(String name)// t1 t2
     44     {
     45         //获取锁。
     46         lock.lock();
     47         try{
     48         while(flag)
     49             try{produce.await();}catch(InterruptedException e){}
     50         this.name = name+count;//商品1
     51         count++;
     52         System.out.println(Thread.currentThread().getName()+"....生产者..."+this.name);//生产了商品1
     53         
     54         //将标记该为true
     55         flag = true;
     56         //执行消费者的唤醒。而且是唤醒一个消费者就行了。
     57         consume.signal();
     58         }
     59         finally{
     60             lock.unlock();//一定要执行。
     61         }
     62     }
     63 
     64     public void out()// t3 t4
     65     {
     66         lock.lock();
     67         try{
     68         while(!flag)
     69             try{consume.await();}catch(InterruptedException e){}
     70         System.out.println(Thread.currentThread().getName()+"....消费者..."+this.name);
     71         //将标记该为flase。
     72         flag = false;
     73         produce.signal();
     74         }
     75         finally{
     76             lock.unlock();
     77         }
     78     }
     79 }
     80 
     81 //2,描述生产者。
     82 class Producer implements Runnable
     83 {
     84     private Resource r ;
     85     //生产者一初始化就要有资源。需要将资源传递到构造函数中。
     86     Producer(Resource r)
     87     {
     88         this.r = r;
     89     }
     90     public void run()
     91     {
     92         while(true)
     93         {
     94             r.set("面包");
     95         }
     96     }
     97 }
     98 
     99 //3,描述消费者。
    100 class Consumer implements Runnable
    101 {
    102     private Resource r ;
    103     //消费者一初始化就要有资源。需要将资源传递到构造函数中。
    104     Consumer(Resource r)
    105     {
    106         this.r = r;
    107     }
    108     public void run()
    109     {
    110         while(true)
    111         {
    112             r.out();
    113         }
    114     }
    115 }
    116 
    117 class ThreadDemo11
    118 {
    119     public static void main(String[] args) 
    120     {
    121         //创建资源对象。
    122         Resource r = new Resource();
    123 
    124         //创建线程任务。
    125         Producer pro = new Producer(r);
    126         Consumer con = new Consumer(r);
    127 
    128         //3,创建线程。
    129         Thread t1 = new Thread(pro);
    130         Thread t2 = new Thread(pro);
    131         Thread t3 = new Thread(con);
    132         Thread t4 = new Thread(con);
    133 
    134         t1.start();
    135         t2.start();
    136         t3.start();
    137         t4.start();
    138     }
    139 }
     1 //接口 Condition示例:
     2 class BoundedBuffer {
     3    final Lock lock = new ReentrantLock();//
     4    final Condition notFull  = lock.newCondition(); //生产。
     5    final Condition notEmpty = lock.newCondition(); //消费。
     6 
     7    final Object[] items = new Object[100];//存储商品的容器。
     8    int putptr/*生产者使用的脚标*/, takeptr,/*消费者使用的角标*/ count;//计数器。
     9 
    10     /*生产者使用的方法,往数组中存储商品。*/
    11    public void put(Object x) throws InterruptedException {
    12      lock.lock();
    13      try {
    14        while (count == items.length) //判断计数器是否已到数据长度。慢了。
    15          notFull.await();//生产者等待。
    16 
    17        items[putptr] = x; //安照角标将商品存储到数组中。
    18 
    19        if (++putptr == items.length)//如果存储的角标到了数组的长度,就将角标归零。
    20            putptr = 0;
    21        ++count;//计数器自增。
    22        notEmpty.signal();//唤醒一个消费者。
    23      } finally {
    24        lock.unlock();
    25      }
    26    }
    27 
    28    public Object take() throws InterruptedException {
    29      lock.lock();
    30      try {
    31        while (count == 0) //如果计数器为零,说明没有商品,消费者需要等待。
    32          notEmpty.await();
    33        Object x = items[takeptr]; //从数组中通过消费者角标获取商品。
    34 
    35        if (++takeptr == items.length) //如果消费者角标等于数组长度,将角标归零。
    36            takeptr = 0;
    37        --count;//计数器自增。
    38        notFull.signal();//唤醒生产者。
    39        return x;
    40      } finally {
    41        lock.unlock();
    42      }
    43    } 
    44  }
  • 相关阅读:
    Model的save方法的使用
    Linux文件属性
    SQL中EXISTS/NOT EXISTS的用法
    SQL中INNER JOIN的用法
    SQL中like的用法
    Group By 和Having总结
    selenium webdriver——XPath 定位
    selenium webdriver——JS滚动到最底部
    selenium webdriver ——执行javascript代码
    requests接口测试——身份认证
  • 原文地址:https://www.cnblogs.com/sun-/p/5401215.html
Copyright © 2011-2022 走看看