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;
}
}
Java技术之如何保证同一资源被多个线程并发访问时的完整性?的更多相关文章
- Java多线程编程核心技术-第2章-对象及变量的并发访问-读书笔记
第 2 章 对象及变量的并发访问 本章主要内容 synchronized 对象监视器为 Object 时的使用. synchronized 对象监视器为 Class 时的使用. 非线程安全是如何出现的 ...
- java多线程编程核心技术(二)--对象及变量的并发访问
1.方法内部的私有变量是线程安全的,实例变量是线程不安全的. 2.A线程先持有object对象的lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法. 3.A ...
- Java多线程编程核心技术,第二章,对象和变量并发访问
1,方法内部变量是线程安全的 2,实例变量非线程安全 3,synchronized是锁对象不是锁方法(锁对象是可以访问非synchronized方法,不可访问同个和其他synchronized方法 4 ...
- Java技术——Java多线程学习
)适合多个相同程序代码的线程区处理同一资源的情况.比如下面这个买票的例子. //使用Thread实现 public static class MyThread extends Thread{ priv ...
- Java多线程编程核心技术(二)对象及变量的并发访问
本文主要介绍Java多线程中的同步,也就是如何在Java语言中写出线程安全的程序,如何在Java语言中解决非线程安全的相关问题.阅读本文应该着重掌握如下技术点: synchronized对象监视器为O ...
- Java多线程编程核心 - 对象及变量的并发访问
1.什么是“线程安全”与“非线程安全”? “非线程安全”会在多个线程对同一对象总的实例变量进行并发访问时发生,产生的后果是“脏读”,也就是取到的数据其实是被更改过的. “线程安全”是以获得的实例变量的 ...
- Java多线程——对象及变量的并发访问
Java多线系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客Java基础系列3:多线程超详细总结,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多线 ...
- Java——多线程之对象及变量的并发访问
Java多线系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客Java基础系列3:多线程超详细总结,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多线 ...
- Java多线程编程核心技术---对象及变量的并发访问(一)
synchronized同步方法 "非线程安全"其实会在多个线程对同一个对象中的实例变量进行并发访问时发生,产生的后果就是"脏读",也就是渠道的数据其实是被更改 ...
随机推荐
- Sql Server 获取存储过程或函数创建语句
通过该语句可以获取到sqlserver 所有的函数名或者存储过程名 SELECT name FROM sysobjects WHERE xtype='P'; 通过该语句可查询出函数或者存储过的的创建语 ...
- Java将ip字符串转换成整数的代码
下面代码是关于Java将ip字符串转换成整数的代码,希望对各位有较大用途. public class IpUtil { public static int Ip2Int(String strIp){ ...
- Pycharm 远程调试
上传后发现成图片了,很模糊.可以看我在百度盘分享pdf文件. https://pan.baidu.com/s/1bYVcAq40SRFtn8qXCPH6TQ
- 当锚点定位遇上position: fixed
<!DOCTYPE html><html> <head> <title>当锚点定位遇上position: fixed</title> < ...
- 通过sqlalchemy操作mysql
# 安装 pip3 install sqlalchemy import sqlalchemy from sqlalchemy import create_enginefrom sqlalchemy.e ...
- TCP聊天工具的实现
由于本人天生愚钝,所以关于聊天工具的编程一直都没学会,尽管网上教程一大堆,但是关于IdTCPClient IdTCPServer 的不多,今天终于学会一些,分享给像我一样纠结的小伙伴,下一步学习多线 ...
- (2018 Multi-University Training Contest 3)Problem L. Visual Cube
//题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6330//题目大意:按照一定格式画出一个 a×b×c 的长方体. #include <b ...
- tomcat文件下目录介绍
主目录下有bin ,conf ,lib ,logs ,temp ,webapps ,work 7个文件夹,下面对它们分别进行介绍: 1.bin目录主要是用来存放tomcat的命令,主要有两大类,一类是 ...
- Mysql 大量Sleep 解决
排查 SHOW GLOBAL VARIABLES LIKE 'wait_timeout'; SHOW GLOBAL VARIABLES LIKE 'interactive_timeout'; 在线更新 ...
- Python统计excel表格中文本的词频,生成词云图片
import xlrd import jieba import pymysql import matplotlib.pylab as plt from wordcloud import WordClo ...