• Java技术学习:如何保证同一资源被多个线程并发访问时的完整性?


    常用的同步方法是采用信号或加锁机制,保证资源在任意时刻至多被一个线程访问。Java语言在多线程编程上实现了完全对象化,提供了对同步机制的良好支持。
    在Java中一共有四种方法支持同步,其中前三个是同步方法,一个是管道方法。管道方法不建议使用,阻塞队列方法在之前已有描述,现只提供前两种实现方法。
    - wait()/notify()方法
    - await()/signal()方法
    - BlockingQueue阻塞队列方法
    - PipedInputStream/PipedOutputStream
    一、生产者类:
    ```
    public class Producer extends Thread { // 每次生产的产品数量
    private int num;
    // 所在放置的仓库
    private Storage storage;
    // 构造函数,设置仓库
    public Producer(Storage storage) {
    this.storage = storage;
    }
     
    // 线程run函数
    public void run() {
    produce(num);
    }
    // 调用仓库Storage的生产函数
    public void produce(int num) {
    storage.produce(num);
    }
    public int getNum() {
    return num;
    }
    public void setNum(int num) {
    this.num = num;
    }
    public Storage getStorage() {
    return storage;
    }
    public void setStorage(Storage storage) {
    this.storage = storage;
    }
    }
     
    ```
    二、消费者类:
    ```
    public class Consumer extends Thread { // 每次消费的产品数量
    private int num;
     
    // 所在放置的仓库
    private Storage storage;
    // 构造函数,设置仓库
    public Consumer(Storage storage) {
    this.storage = storage;
    }
    // 线程run函数
    public void run() {
    consume(num);
    }
    // 调用仓库Storage的生产函数
    public void consume(int num) {
    storage.consume(num);
    }
    // get/set方法
    public int getNum() {
    return num;
    }
    public void setNum(int num) {
    this.num = num;
    }
    public Storage getStorage() {
    return storage;
    }
    public void setStorage(Storage storage) {
    this.storage = storage;
    }
    }
    ```
    仓库类:(wait()/notify()方法)
    ```
    public class Storage { // 仓库最大存储量
    private final int MAX_SIZE = 100;
    // 仓库存储的载体
    private LinkedList<Object> list = new LinkedList<Object>();
    // 生产num个产品
    public void produce(int num) {
    // 同步代码段
    synchronized (list) {
    // 如果仓库剩余容量不足
    while (list.size() + num > MAX_SIZE) {
    System.out.print("【要生产的产品数量】:" + num);
    System.out.println(" 【库存量】:" + list.size() + " 暂时不能执行生产任务!");
     
    try {
    list.wait();// 由于条件不满足,生产阻塞
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
     
    // 生产条件满足情况下,生产num个产品
    for (int i = 1; i <= num; ++i) {
    list.add(new Object());
    }
     
    System.out.print("【已经生产产品数】:" + num);
    System.out.println(" 【现仓储量为】:" + list.size());
     
    list.notifyAll();
    }
    }
     
    // 消费num个产品
    public void consume(int num) {
    // 同步代码段
    synchronized (list) {
    // 如果仓库存储量不足
    while (list.size() < num) {
    System.out.print("【要消费的产品数量】:" + num);
    System.out.println(" 【库存量】:" + list.size() + " 暂时不能执行生产任务!");
     
    try {
    // 由于条件不满足,消费阻塞
    list.wait();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
     
    // 消费条件满足情况下,消费num个产品
    for (int i = 1; i <= num; ++i) {
    list.remove();
    }
     
    System.out.print("【已经消费产品数】:" + num);
    System.out.println(" 【现仓储)量为】:" + list.size());
     
    list.notifyAll();
    }
    }
     
    // get/set方法
    public LinkedList<Object> getList() {
    return list;
    }
     
    public void setList(LinkedList<Object> list) {
    this.list = list;
    }
     
    public int getMAX_SIZE() {
    return MAX_SIZE;
    }
    }
     
    ```
    仓库类:(await()/signal()方法)
    ```
    public class Storage { // 仓库最大存储量
    // 仓库最大存储量
    private final int MAX_SIZE = 100;
    // 仓库存储的载体
    private LinkedList<Object> list = new LinkedList<Object>();
    // 锁
    private final Lock lock = new ReentrantLock();
    // 仓库满的条件变量
    private final Condition full = lock.newCondition();
    // 仓库空的条件变量
    private final Condition empty = lock.newCondition();
    // 生产num个产品
    public void produce(int num) {
    // 获得锁
    lock.lock();
     
    // 如果仓库剩余容量不足
    while (list.size() + num > MAX_SIZE) {
    System.out.print("【要生产的产品数量】:" + num);
    System.out.println(" 【库存量】:" + list.size() + " 暂时不能执行生产任务!");
    try {
    // 由于条件不满足,生产阻塞
    full.await();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
     
    // 生产条件满足情况下,生产num个产品
    for (int i = 1; i <= num; ++i) {
    list.add(new Object());
    }
    System.out.print("【已经生产产品数】:" + num);
    System.out.println(" 【现仓储量为】:" + list.size());
    // 唤醒其他所有线程
    full.signalAll();
    empty.signalAll();
     
    // 释放锁
    lock.unlock();
    }
    // 消费num个产品
    public void consume(int num) {
    // 获得锁
    lock.lock();
    // 如果仓库存储量不足
    while (list.size() < num) {
    System.out.print("【要消费的产品数量】:" + num);
    System.out.println(" 【库存量】:" + list.size() + " 暂时不能执行生产任务!");
    try {
    // 由于条件不满足,消费阻塞
    empty.await();
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    // 消费条件满足情况下,消费num个产品
    for (int i = 1; i <= num; ++i) {
    list.remove();
    }
    System.out.print("【已经消费产品数】:" + num);
    System.out.println(" 【现仓储)量为】:" + list.size());
    // 唤醒其他所有线程
    full.signalAll();
    empty.signalAll();
    // 释放锁
    lock.unlock();
    }
    // set/get方法
    public int getMAX_SIZE() {
    return MAX_SIZE;
    }
    public LinkedList<Object> getList() {
    return list;
    }
    public void setList(LinkedList<Object> list) {
    this.list = list;
    }
    }
  • 相关阅读:
    网卡中断负载均衡
    【Linux】tcp缓冲区大小的默认值、最大值
    ssh RSA key变化后处理
    drop_caches控制page cache
    Linux的page cache使用情况/命中率查看和操控
    如何在vscode中调试vue-cli项目?
    vue-cli || webpack 打包的时候css里面写的背景图片的路径出错问题
    charles 的安装和手机配置 (我用的win7系统 ,和 iphone8 的配置)
    如何结合插件 vue-lazyload 来简单实现图片懒加载?
    cordova 和 java ( JDK ) 和 android-studio (SDK)的初始安装和配置
  • 原文地址:https://www.cnblogs.com/qf-dd/p/10419872.html
Copyright © 2020-2023  润新知