常用的同步方法是采用信号或加锁机制,保证资源在任意时刻至多被一个线程访问。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技术之如何保证同一资源被多个线程并发访问时的完整性?的更多相关文章

  1. Java多线程编程核心技术-第2章-对象及变量的并发访问-读书笔记

    第 2 章 对象及变量的并发访问 本章主要内容 synchronized 对象监视器为 Object 时的使用. synchronized 对象监视器为 Class 时的使用. 非线程安全是如何出现的 ...

  2. java多线程编程核心技术(二)--对象及变量的并发访问

    1.方法内部的私有变量是线程安全的,实例变量是线程不安全的. 2.A线程先持有object对象的lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法. 3.A ...

  3. Java多线程编程核心技术,第二章,对象和变量并发访问

    1,方法内部变量是线程安全的 2,实例变量非线程安全 3,synchronized是锁对象不是锁方法(锁对象是可以访问非synchronized方法,不可访问同个和其他synchronized方法 4 ...

  4. Java技术——Java多线程学习

    )适合多个相同程序代码的线程区处理同一资源的情况.比如下面这个买票的例子. //使用Thread实现 public static class MyThread extends Thread{ priv ...

  5. Java多线程编程核心技术(二)对象及变量的并发访问

    本文主要介绍Java多线程中的同步,也就是如何在Java语言中写出线程安全的程序,如何在Java语言中解决非线程安全的相关问题.阅读本文应该着重掌握如下技术点: synchronized对象监视器为O ...

  6. Java多线程编程核心 - 对象及变量的并发访问

    1.什么是“线程安全”与“非线程安全”? “非线程安全”会在多个线程对同一对象总的实例变量进行并发访问时发生,产生的后果是“脏读”,也就是取到的数据其实是被更改过的. “线程安全”是以获得的实例变量的 ...

  7. Java多线程——对象及变量的并发访问

    Java多线系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客Java基础系列3:多线程超详细总结,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多线 ...

  8. Java——多线程之对象及变量的并发访问

    Java多线系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客Java基础系列3:多线程超详细总结,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多线 ...

  9. Java多线程编程核心技术---对象及变量的并发访问(一)

    synchronized同步方法 "非线程安全"其实会在多个线程对同一个对象中的实例变量进行并发访问时发生,产生的后果就是"脏读",也就是渠道的数据其实是被更改 ...

随机推荐

  1. easyui datagrid 后台分页,前端如何处理

    module.exports = { queryMethod(){ let params = checkQueryParams.call(this); if (!params) { return; } ...

  2. Python入门学习例子——从Hao123获取图片

    import urllib.requestimport re #获取html页面内容def getHtml(url): data=urllib.request.urlopen(url) pageCon ...

  3. 以太坊Bootstrap和Kademlia算法实现逻辑简介(基于cpp-ethereum)

  4. 2017-9-24模拟赛T1 个人卫生综合征(school.*)

    题目 每天 BBS 都要从家里经过城市中的一段路到学校刷五三.城市中一共有 n 个路口和 m 条双向道路,每条双向道路都连接着两个路口 a i .b i 且有一定的时间花费 v i .BBS家编号为 ...

  5. sql注入练习,sqli-labs writeup

    一.Less-1 1.判断是否存在注入 URL中输入“?id=1”,发现回显有变化,说明存在注入: 2.判断闭合字符,注释后面的内容 输入“   ?id=1'  ”,回显为  "1" ...

  6. kettle 在javascrip代码组件中使用fireToDB()函数实现自定义数据库查询

    kettele里面的demo如下; var strConn = "MY Connection";var strSQL = "SELECT COUNT(*) FROM .. ...

  7. 神州数码标准访问控制列表配置(ACL)

    实验要求:熟练掌握标准访问控制列表配置方法 拓扑如下 R1 enable 进入特权模式 config 进入全局模式 hostname R1 修改名称 interface s0/1 进入端口 ip ad ...

  8. 【oracle入门】SQL的命令动词

      SQL的功能 命令动词 数据定义 CREATE,DROP,ALTER 数据操纵 SELECT,INSERT,UPDATE,DELETE 数据控制 CRANT,REVOKE

  9. javamail发邮件

    使用JavaMail发送一封简单邮件的步骤:(1)创建代表邮件服务器的网络连接信息的Session对象.(2)创建代表邮件内容的Message对象(3)创建Transport对象.连接服务器.发送Me ...

  10. ssh 无秘钥登录

    三台centos 一台服务器192.168.2.152 一台客户端192.168.2.142 一台客户端192.168.2.151 (1)产生无密钥 [root@localhost ~]#  ssh- ...