zoukankan      html  css  js  c++  java
  • java中线程同步问题

      先不多说,直接上个例子,著名的生产者消费者问题。

     1 public class ProducerConsumer {
     2     public static void main(String[] args) {
     3         SyncStack ss = new SyncStack();
     4         Producer p = new Producer(ss);
     5         Consumer c = new Consumer(ss);
     6         new Thread(p).start();//生产者线程
     7         new Thread(c).start();//消费者线程
     8     }
     9 }
    10 /**
    11 消费的物品---窝头
    12 **/
    13 class WoTou {
    14     int id; 
    15     WoTou(int id) {
    16         this.id = id;
    17     }
    18     public String toString() {
    19         return "WoTou : " + id;
    20     }
    21 }
    22 /**
    23 消费的空间---堆栈
    24 **/
    25 class SyncStack {
    26     int index = 0;
    27     WoTou[] arrWT = new WoTou[6];
    28     
    29     public synchronized void push(WoTou wt) {
    30         while(index == arrWT.length) {//是while而不是if的原因,当wait被打断的时候依旧要检查下堆栈是否满了,否则,由于之前判断过index,从而会跳过判断而导致错误
    31             try {
    32                 this.wait();
    33             } catch (InterruptedException e) {
    34                 e.printStackTrace();
    35             }
    36         }
    37         this.notifyAll();        
    38         arrWT[index] = wt;
    39         index ++;
    40     }
    41     
    42     public synchronized WoTou pop() {
    43         while(index == 0) {
    44             try {
    45                 this.wait();
    46             } catch (InterruptedException e) {
    47                 e.printStackTrace();
    48             }
    49         }
    50         this.notifyAll();
    51         index--;
    52         return arrWT[index];
    53     }
    54 }
    55 
    56 /**
    57 生产者类
    58 **/
    59 class Producer implements Runnable {
    60     SyncStack ss = null;
    61     Producer(SyncStack ss) {
    62         this.ss = ss;
    63     }
    64     
    65     public void run() {
    66         for(int i=0; i<20; i++) {
    67             WoTou wt = new WoTou(i);
    68             ss.push(wt);
    69 System.out.println("生产了:" + wt);
    70             try {
    71                 Thread.sleep((int)(Math.random() * 200));
    72             } catch (InterruptedException e) {
    73                 e.printStackTrace();
    74             }            
    75         }
    76     }
    77 }
    78 /**
    79 消费者类
    80 **/
    81 class Consumer implements Runnable {
    82     SyncStack ss = null;
    83     Consumer(SyncStack ss) {
    84         this.ss = ss;
    85     }
    86     
    87     public void run() {
    88         for(int i=0; i<20; i++) {
    89             WoTou wt = ss.pop();
    90 System.out.println("消费了: " + wt);
    91             try {
    92                 Thread.sleep((int)(Math.random() * 1000));
    93             } catch (InterruptedException e) {
    94                 e.printStackTrace();
    95             }            
    96         }
    97     }
    98 }

     效果如图:

    synchronized的引入,学过数据库系统和操作系统的朋友应该会有所了解,对于共享资源,当一个线程占用的时候不能被其他线程操作,和操作系统的原子操作的原理有些相似。

    对于synchronized的理解:

    synchronized(对象){

    同步代码块

    }

    当是非static synchronized函数时,默认对象为this;当为是static synchronized函数时,默认为当前对象.class。

    而wait,notify,notifyAll时,前面必须指定锁,即对象(原因:因为如果出现synchronized嵌套的时候会出错,这个好比一个游戏,一个锁是一组,只有在一组之内wait,notify,notifyAll有效,而对于另外一个组是无效的。)

      wait的引入:例如上题堆栈中只能放6个窝头,但是当堆栈中有6个窝头的时候,生产者获得对象锁的时候就不能生产了,因此,生产者就会进入wait池,同时又会释放对象锁。

      notify的引入:唤醒wait池中的一个线程(ps:只能唤醒别的线程,不能唤醒自己)

      notifyall的引入:唤醒wait池中的所有线程

      在最后,给大家说下wait和sleep的区别吧,个人理解:

    1.wait是Object类中方法,会抛出InteruptException,sleep是Thread类中的方法,wait方法只用在获得对象锁得时候才能用,否则会抛异常;

    2.wait方法会释放对象锁,但是sleep不会释放对象锁;

    3.wait后的线程需要其他的线程去唤醒,但是sleep的线程在规定的时间后会自动唤醒。

  • 相关阅读:
    Pro Andorid3第二章:设置开发环境
    Seminar 记录
    安装CGAL
    Literature review
    第七章:清楚简洁的英文 《英语科技写作(文法与修辞原则)》by 方克涛
    幻灯片制作去除模板背景
    vs2008下设置.h, .lib和 .dll 的路径配置全图及其意义
    配置环境变量
    PPT制作技巧
    #include文件时用双引号和尖括号的区别
  • 原文地址:https://www.cnblogs.com/liujunming/p/4375864.html
Copyright © 2011-2022 走看看