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;

}

}

原文地址:https://www.cnblogs.com/qf-dd/p/10419872.html

时间: 2024-10-11 10:40:27

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

java技术学习步骤

java技术学习步骤 ? 一.入门 二.基础巩固 三.深入学习 四.源码剖析 五.总结分析 语言基础 <java核心技术卷I> <java编程思想> <java核心技术卷II> <Effective java > <java 特种兵> ? ? 框架技术 Struts2:<深入浅出Struts2> ? ? ? ? ? ? ?<Strut2实战> Hibernate:<精通Hibernate> Spring:<

java技术学习路线

随着互联网行业的高速发展,编程无疑越来越深入人心.而Java是当前世界非常流行的编程语言之一,代表着很高的薪资和很好的待遇.现在社会也确实有很多人渐渐的对java产生了不小的兴趣,也想在Java这个领域分一份羹,但苦于入不得其门,本文针对Java初学者介绍一下Java的学习方法. 近期对Java这门语言也有了比以前更深刻的认识,学习了Java的一些基本语法,比如数据类型.运算符.程序流程控制.数组,也在逐渐上升到面向对象编程这一概念.而Java核心的核心就是面向对象思想,只要能够掌握好面向对象这

Java技术学习路线图

一:常见模式与工具 学习Java技术体系,设计模式,流行的框架与组件是必不可少的: 常见的设计模式,编码必备 Spring5,做应用必不可少的最新框架 MyBatis,玩数据库必不可少的组件 二:工程化与工具 工欲善其事必先利其器,不管是小白,还是资深开发,玩Java技术体系,选择好的工具,提升开发效率和团队协作效率,是必不可少的: Maven,项目管理 Jenkins,持续集成 Sonar,代码质量管理 Git,版本管理 三:分布式架构 高并发,高可用,海量数据,没有分布式的架构知识肯定是玩不

新兵日记--java多线程学习(一)  --如何创建线程

java 多线程的实现方法 可以通过继承Thread类和实现Runnable接口来实现,而Thread类实际上实现了Runnable接口 ,两种创建线程的方法性质是一样的,并没有什么本质区别 Thread类 1. 创建MyThread 类并继承Thread类 public class MyThread extends Thread{} 2. 在MyThread类中重写 Thread类的run()方法,值得一提的是Thread类的run()方法是实现了Runnable接口,所以继承Thread类和

Java多线程技术学习笔记(二)

目录: 线程间的通信示例 等待唤醒机制 等待唤醒机制的优化 线程间通信经典问题:多生产者多消费者问题 多生产多消费问题的解决 JDK1.5之后的新加锁方式 多生产多消费问题的新解决办法 sleep和wait的区别 停止线程的方式 守护线程 线程的其他知识点 一.线程间的通信示例 返目录回 多个线程在处理同一资源,任务却不同. 假设有一堆货物,有一辆车把这批货物往仓库里面运,另外一辆车把前一辆车运进仓库的货物往外面运.这里货物就是同一资源,但是两辆车的任务却不同,一个是往里运,一个是往外运. 下面

java web 学习五(servlet开发1)

一.Servlet简介 Servlet是sun公司提供的一门用于开发动态web资源的技术. Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤: 1.编写一个Java类,实现servlet接口. 2.把开发好的Java类部署到web服务器中. 按照一种约定俗成的称呼习惯,通常我们也把实现了servlet接口的java程序,称之为Servlet 二.Servlet的运行过程 Servlet程序是由WEB

最值得收藏的java技术博客(Java篇)

第一个:java_my_life 作者介绍:找不到原作者信息.大概做了翻阅全部是2012年的博客. 博客主要内容:主要内容是关于Java设计模式的一些讲解和学习笔记,在相信对学习设计模式的同学帮助很大.在一望无际的Java博文中有那么一两篇JavaScript文章,就算两篇Javascript的质量不是很高,其它教程也是能很好的帮助到在学习中的朋友. 博客关键词:JAVA与模式.简单工厂模式.工厂方法.抽象工厂.单例.建造.原型.适配器.合成.迭代.观察者.模板方法.策略.不变.桥梁.门面.代理

Java技术体系大全,准备面试的可以参考一下!

1. JAVA技术体系1.1 Java程序员 ·高级特性 反射.泛型.注释符.自动装箱和拆箱.枚举类.可变参数.可变返回类型.增强循环.静态导入 ·核心编程 IO.多线程.实体类.集合类.正则表达式.XML和属性文件 ·图形编程 AWT(Java2D/JavaSound/JMF).Swing.SWT.JFace ·网路编程 Applet.Socket/TCP/UDP.NIO.RMI.CORBA ·Java语法基础 类.抽象类.接口.最终类.静态类.匿名类.内部类.异常类.编码规范 ·Java开发

技术学习步骤

java技术学习步骤 ? 一.入门 二.基础巩固 三.深入学习 四.源码剖析 五.总结分析 语言基础 <java核心技术卷I> <java编程思想> <java核心技术卷II> <Effective java > <java 特种兵> ? ? 框架技术 Struts2:<深入浅出Struts2> ? ? ? ? ? ? ?<Strut2实战> Hibernate:<精通Hibernate> Spring:<