zoukankan      html  css  js  c++  java
  • Demo

    多线程学习笔记3——多线程的互斥和同步

    线程的互斥

    Producer是生产者线程, Consumer是消费者线程,Buffer是生产者与消费者的共享缓冲区, 必须实现读,写的同步.ProducerConsumerProblem 是演示生0read类,在run()创建了方法中生产6产品放到Buffer中,消费者Consumer创建了2个线程分别消费3个物品.

    • Buffer类中利用available变量实现了生产者生成出物品时可以消费.
      消费方法get()当available为false时,调用方法wait()等待.当available为true时消费,然后后把available改为false并调用notifyAll()唤醒生产者线程.
      生产方法put(),当available为true也就是容器为空时,生产者才可以想buffer中放产品,如果不能放则等待,放好后吧available改为true说明容器中有产品,消费这可以消费了,接着调用notifyAll()唤醒等待的消费者线程.

    其中synchronize同步关键字,当一个线程用这个方法操作的时候,不允许其他线程对这个方法进行操作,从而保持主方法中创建的2个消费者线程保持互斥.

    //生产者线程
    class Producer extends Thread{
        private Buffer buffer;
        private int number;
        public Producer(Buffer buffer, int number){
            this.buffer = buffer;
            this.number = number;
        }
        public void run(){
            for (int i = 0;i < 6;){
                buffer.put(i);
                System.out.println("生产者#"+number+"生产"+(i++));
                try {
                    Thread.sleep((int)(Math.random()*2000));
                }catch (InterruptedException exc){}
            }
        }
    }
    
    //消费者线程
    class Consumer extends Thread{
        private Buffer buffer;
        private int number;
    
        public Consumer (Buffer buffer, int number){
            this.buffer = buffer;
            this.number = number;
        }
        public void run(){
            for (int i=0;i<3;i++){
                int v = buffer.get();
                System.out.println("消费这#"+number+"消费"+v);
            }
        }
    }
    
    //生产者与消费者共享的缓冲区,必须实现读,写的同步
    class Buffer {
        private int contents;
        private boolean available = false;
    
        public synchronized int get() {
            while (!available) {
                try {
                    //wait()会让线程挂起,直到通知到它继续执行!挂起的线程会存放到等待队列中,按照wait的先后顺序存放。
                    this.wait();
                } catch (InterruptedException exc) {
                }
            }
            int value = contents;
            //消费着取出内容,改变存取控制available
            available = false;
            System.out.println("取出" + contents);
            //notify()通知等待队列中的第一个线程,notifyAll()通知的是等待队列中的所有线程
            this.notify();
            return value;
        }
    
        public synchronized void put(int value) {
            while (available) {
                try {
                    this.wait();
                } catch (InterruptedException exc) {
                }
            }
            contents = value;
            //生成这放入内容,改变存取控制
            available = true;
            System.out.println("放入" + contents);
            this.notifyAll();
        }
    }
    
    public class ProducerConsumerProblem {
        public static void main(String[] args) {
            Buffer buffer = new Buffer();
            new Producer(buffer,101).start();
            new Consumer(buffer,200).start();
            new Consumer(buffer,201).start();
        }
    }
    

    所以访问共享资源的方法都必须是synchronize的,否则程序肯定会出错.

    线程的同步

  • 相关阅读:
    用SQL SERVER取分组数据第一条:查出每个班级的成绩第一名
    [转]spring beans.xml
    [转]为什么要使用框架
    MySQL 5.6 for Windows 解压缩版配置安装
    [转]hql 语法与详细解释
    [转]slf4j + log4j原理实现及源码分析
    [转]最详细的Log4j使用教程
    yii2 checkbox 的使用实例
    Magento Order 状态详解
    yii2 设置多个入口文件
  • 原文地址:https://www.cnblogs.com/kongw/p/13893396.html
Copyright © 2011-2022 走看看