`
leichenlei
  • 浏览: 124485 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java并发(五、保护块)

    博客分类:
  • java
 
阅读更多

线程必须经常协调他们的活动。最普通的协调方法是保护块(guarded block)。以循环条件开始的代码块必须在循环条件为真时代码块才能够执行。为了正确操作有许多步骤需要遵守。

假设,比如 guardedJoy方法直到共享变量joy被另一个线程修改才会执行。理论上,这个方法一直在循环直到满足条件,但是这个循环很浪费,因为它在等待的时候不停的在运行。

public void guardedJoy() {

// Simple loop guard. Wastes

// processor time. Don't do this!

while(!joy) {}

System.out.println("Joy has been achieved!");

}

 

一个更有效的保护(guard)是调用Object.wait去暂停当前线程。wait的调用不会返回直到其他的线程发出某个特别的事件已经发生的通知-虽然不见得是这个线程正在等待的事件。(有可能是发生了异常)

public synchronized guardedJoy() {

// This guard only loops once for each special event, which may not

// be the event we're waiting for.

while(!joy) {

try {

wait();

} catch (InterruptedException e) {}

}

System.out.println("Joy and efficiency have been achieved!");

}

 

 


注意:在等待测试条件的循环代码中一直调用wait方法。不要假设中断(interrupt)是你要等待的特定条件,因为条件仍然还是true


 

像许多暂停执行的方法,wait能够抛出InterruptedException。在这个例子中,我们能够忽略这个异常-我们仅仅只关心joy的值

为什么这个版本的guardJoy要同步?假设d是我们用来调用wait的对象。当一个线程调用d.wait,它肯定拥有d的内置锁-否则会抛出一个错误。在同步方法里调用wait方法是一个获得内置锁的简单方法

wait被调用,线程会释放掉锁并且暂停执行。在未来的某个时间,另外一个线程将会获得同样的锁并且调用Object.notifyAll,这会通知所有在等待lock的线程有一些重要的事情发生了

public synchronized notifyJoy() {

joy = true;

notifyAll();

}

有时在第二个线程释放掉锁后,第一个线程重新获得这个锁并且从调用的wait中返回恢复运行。


注意:有第二个通知方法,notify,只能唤醒一个线程。因为notify不允许你指定要唤醒的线程,这个在大规模并行程序中有用处-即,程序中有大量的线程,并且都在做类似的事情,在这样的程序中,你不必在意哪个线程被唤醒了。


让我们使用保护块(guarded blocks)来创建一个生产者-消费者应用程序。这类程序在线程间共享数据:生产者,负责生产数据,消费者,负责使用数据。这2个线程使用共享对象通信。协调是必不可少的:消费者不能够在生产者递送数据前检索它,并且如果消费者还没有取得老数据生产者不能够递送新数据

在这个例子中,数据是一系列的文本消息,通过一个Drop对象共享。

public class Drop {

// Message sent from producer

// to consumer.

private String message;

// True if consumer should wait

// for producer to send message,

// false if producer should wait for

// consumer to retrieve message.

private boolean empty = true;

public synchronized String take() {

// Wait until message is

// available.

while (empty) {

try {

wait();

} catch (InterruptedException e) {}

}

// Toggle status.

empty = true;

// Notify producer that

// status has changed.

notifyAll();

return message;

}

public synchronized void put(String message) {

// Wait until message has

// been retrieved.

while (!empty) {

try {

wait();

} catch (InterruptedException e) {}

}

// Toggle status.

empty = false;

// Store message.

this.message = message;

// Notify consumer that status

// has changed.

notifyAll();

}

}

生产者线程在producer中定义,发送一系列熟悉的信息。“DONE”表明所有的数据都发送完了。为了模拟真实世界程序的不可预知的特性,生产者线程在消息发送之间会暂停一个随机的间隔。

import java.util.Random;

public class Producer implements Runnable {

private Drop drop;

public Producer(Drop drop) {

this.drop = drop;

}

public void run() {

String importantInfo[] = {"Mares eat oats","Does eat oats","Little lambs eat ivy","A kid will eat ivy too"};

Random random = new Random();

for (int i = 0;i < importantInfo.length;i++) {

drop.put(importantInfo[i]);

try {

Thread.sleep(random.nextInt(5000));

} catch (InterruptedException e) {}

}

drop.put("DONE");

}

}

消费者线程定义在Consumer类中,简单的检索信息并且打印它们,知道检索到“DONE.这个线程也会暂停一个随机的间隔

import java.util.Random;

public class Consumer implements Runnable {

private Drop drop;

public Consumer(Drop drop) {

this.drop = drop;

}

public void run() {

Random random = new Random();

for (String message = drop.take();! message.equals("DONE");

message = drop.take()) {

System.out.format("MESSAGE RECEIVED: %s%n", message);

try {

Thread.sleep(random.nextInt(5000));

} catch (InterruptedException e) {}

}

}

}

最后,这是main线程,定义在ProducerConsumerExample中,并且启动生产者和消费者线程

public class ProducerConsumerExample {

public static void main(String[] args) {

Drop drop = new Drop();

(new Thread(new Producer(drop))).start();

(new Thread(new Consumer(drop))).start();

}

}


注意:Drop是用来演示保护快的。为了避免重复,在写你自己数据分享对象之前,看一下java集合框架中已有的数据结构。更多信息,看问题和练习一章。


分享到:
评论

相关推荐

    Java并发编程实践 PDF 高清版

    Java 5以及6在开发并发程序取得了显著的进步,提高了Java虚拟机的性能,提高了并发类的可伸缩性,并加入了丰富的新并发构建块。在本书中,这些便利工具的创造者不仅解释了它们究竟如何工作、如何使用,同时,还阐释...

    JAVA并发编程实践_中文版(1-16章全)_1/4

    2.4 用锁来保护状态 2.5 活跃度与性能 第3章 共享对象 3.1 可见性 3.2 发布和逸出 3.3 线程封闭 3.4 不可变性 3.5 安全发布 . 第4章 组合对象 4.1 设计线程安全的类 4.2 实例限制 4.3 委托线程安全 4.4 向已有的线程...

    Java并发编程实战

    Java并发编程实战 本书深入浅出地介绍了Java线程和并发,是一本完美的Java并发参考手册。书中从并发性和线程安全性的基本概念出发,介绍了如何使用类库提供的基本并发构建块,用于避免并发危险、构造线程安全的类及...

    Java并发编程part2

    中文完整版的Java并发编程实践PDF电子书 作者:Brian Gogetz Tim Peierls Joshua Bloch Joseph Bowbeer David Holmes Doug Lea 译者:韩锴 方秒 目录 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的优点 1.3 ...

    Java并发编程实践part1

    中文完整版的Java并发编程实践PDF电子书 作者:Brian Gogetz Tim Peierls Joshua Bloch Joseph Bowbeer David Holmes Doug Lea 译者:韩锴 方秒 目录 第1章 介绍 1.1 并发的(非常)简短历史 1.2 线程的优点 1.3 ...

    Java理论与实践:非阻塞算法简介

    Java语言中主要的同步手段就是synchronized关键字,它强制实行互斥,确保执行synchronized块的线程的动作,能够被后来执行受相同锁保护的synchronized块的其他线程看到。在使用得当的时候,内在锁可以让程序做到线程...

    Java高级程序设计-多线程(二).pptx

    这个时候需要在线程中加入对数据的保护机制,从而达到防止并发引起的数据不准确。 Java高级程序设计-多线程(二)全文共34页,当前为第8页。 3.1.2 同步代码块的使用 Java中多线程中引入了同步监视器,使用同步监视器...

    javaSE代码实例

    第16章 多线程——Java中的并发协作 343 16.1 线程的基本知识 343 16.1.1 多线程编程的意义 343 16.1.2 定义自己的线程 344 16.1.3 创建线程对象 345 16.1.4 启动线程 347 16.1.5 同时使用多个线程 ...

    net学习笔记及其他代码应用

    protected : 保护成员,该类内部和继承类中可以访问。 public : 公共成员,完全公开,没有访问限制。 internal: 在同一命名空间内可以访问。 2 .列举ASP.NET 页面之间传递值的几种方式。 答. 1.使用QueryString,...

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串

    组成:表空间、段、区、块的组成层次 六、 oracle安装、卸载和启动  硬件要求 物理内存:1GB 可用物理内存:50M 交换空间大小:3.25GB 硬盘空间:10GB  安装 1. 安装程序成功下载,将会得到如下2个文件: ...

    OCPOCA认证考试指南全册:Oracle Database 11g(1Z0-051,1Z0-052,1Z0-053)--详细书签版(第2/2部分)

    1.4.5 Java池 21 1.4.6 流池 22 1.5 实例进程结构 23 1.5.1 SMON 24 1.5.2 PMON 24 1.5.3 DBWn 24 1.5.4 LGWR 26 1.5.5 CKPT 27 1.5.6 MMON 27 1.5.7 MMNL 28 1.5.8 MMAN 28 1.5.9 ARCn 28 1.5.10 RECO...

    OCPOCA认证考试指南全册:Oracle Database 11g(1Z0-051,1Z0-052,1Z0-053)--详细书签版(第1/2部分)

    1.4.5 Java池 21 1.4.6 流池 22 1.5 实例进程结构 23 1.5.1 SMON 24 1.5.2 PMON 24 1.5.3 DBWn 24 1.5.4 LGWR 26 1.5.5 CKPT 27 1.5.6 MMON 27 1.5.7 MMNL 28 1.5.8 MMAN 28 1.5.9 ARCn 28 1.5.10 RECO...

    ORACLE9i_优化设计与系统调整

    §7.3.1 Oracle系统有关目录所有文件的保护 94 §7.3.2 避免新用户使用默认system系统表空间 94 §7.4 Oracle系统所在服务器的独立性 94 第9章 项目分析、设计与管理 94 §9.1 项目分析要点考虑 95 §9.1.1 对应用...

    asp.net知识库

    第2章 并发操作的一致性问题 (2) Using sqlite with .NET Visual Studio 2005 中的新 DataSet 特性 MySQL 和 .Net2.0配合使用 与DotNet数据对象结合的自定义数据对象设计 (二) 数据集合与DataTable 与DotNet数据对象...

Global site tag (gtag.js) - Google Analytics