常用的同步方法是采用信号或加锁机制,保证资源在任意时刻至多被一个线程访问。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. Excel汉字转换拼音首字母缩写的函数

    打开Excel->工具->宏->Viaual Basic编辑器在弹出来的窗口中对着VBAproject点右键->插入->模块下面会出现一个名为"模块1" ...

  2. JDK 1.8 -> 1.7

    电脑刚开始装的是1.8 version, 然后又需要用到1.7. 所以就要把1.8 降为1.7, 网上有很多说把1.8删掉,这种做法我是不建议的,那么要用的时候呢?又得装回来多蛋疼.. JDK 1.8 ...

  3. NPOI处理Word文本中段落编号

    NPOI的XWPFParagraph对象中,是无法直接读取段落编号的,然而可以读取的是编号的样式名称(GetNumFmt),编号分组ID(GetNumID),编号样式(NumLevelText)等.具 ...

  4. selenium中的对文本进行全选,复制,粘贴,剪切和删除的操作

    # 键盘全选操作from selenium.webdriver.common.keys import Keysdriver.find_element_by_css_selector('#key-dem ...

  5. 52 和 52Rc 通过IIC写入数据

  6. Qt的类:qfileinfogatherer

    这篇文章中,探索Qt中的类qfileinfogatherer类,先给出私有类头文件.我们先想一想要形成一个信息采集者,需要什么?需要一个线程,当文件信息发生变化的时候,作为一个槽来接收信号. 先预备一 ...

  7. vimrc配置

    "=========================================================================" DesCRiption 适合 ...

  8. Tomcat配置SSL后使用HTTP后跳转到HTTPS

    Tomcat配置好SSL后将HTTP请求自动转到HTTPS需要在TOMCAT/conf/web.xml的未尾加入以下配置: <login-config> <!-- Authoriza ...

  9. QA Report

  10. Flask 上下文管理

    为什么用threading.local? 我们都知道线程是由进程创建出来的,CPU实际执行的也是线程,那么线程其实是没有自己独有的内存空间的,所有的线程共享进程的资源和空间,共享就会有冲突,对于多线程 ...