Guarded Blocks 保护块
线程经常需要协调它们的活动,最常用的协调方法是保护块。这样的块是以轮询一个条件开始,这个条件值必须是true,在块处理前。为了正确做到这样,有大量的步骤需要遵守。
例如,guardedJoy 是一个方法,直到一个共享变量joy被另外一个线程设置了才会执行。这样的方法,理论上,简单的循环直到条件满足,但是了这样的循环是耗费的,因为它不断地在等待中执行。
public void guardedJoy() {
// Simple loop guard. Wastes
// processor time. Don't do this!
while(!joy) {}
System.out.println("Joy has been achieved!");
}
一种更有效的保护是调用object.wait来暂停当前线程。wait的调用不会返回直到领一个线程已经发不了一个通知,一些特殊的事件可能发生。虽然不是这个线程正在等待的事件:
public synchronized void 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) {}
}
注意:总是调用循环中的wait来测试正在等待的条件。不要假设中断(interrupt)是你正在等待的条件或者那个条件是true。
像许多暂停执行的方法,wait会抛出InterruptedException。在这个例子中,我们能忽略这个异常,仅仅关注joy的值。
为什么这个版本的guardedJoy是同步的?假设d是我们用来调用wait的对象。当一个线程调用d.wait,它必须拥有d的内在锁---否则将抛出一个错误。在一个同步方法中调用wait是一种简单的方式获取内在锁。
当wait被调用,那个线程就释放锁并暂停执行。在不远的将来,另外一个线程将获取同样的锁并调用object.notifyAll,通知在这个锁上等待的所有线程,一些重要的事情发生了。
public synchronized notifyJoy() {
joy = true;
notifyAll();
}
在第二个线程释放了锁后的一段时间,第一个线程重新获取锁并从wait的调用通过返回继续执行。
注意:有第二个通知方法,notify,唤醒一个单一线程。因为notify不允许你指定要唤醒的线程,只有在大规模并行的应用程序中有用---即,程序中有大量的线程,所有的做那相似的工作。在这样的应用程序中,你不必在意哪个线程被唤醒。
让我们使用保护块创建一个生产者--消费者应用程序。这类的应用在两个线程之间共享数据:生产者创建数据,消费者使用数据做一些事情。两个线程使用一个共享对象通信。协调就是必须的:在生产者传递数据前,消费者不必试着去获取它,并且生产者也不必试着去传递新的数据,如果消费者还没有获取旧的数据。
在这个例子中,数据是一系列的文本信息,通过一个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) {}
}
}
}
最后,这是主线程,以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();
}
}
注意: The Drop class was written in order to demonstrate guarded blocks. To avoid re-inventing the wheel, examine the existing data structures in the Java Collections Framework before trying to code your own data-sharing objects. For more information, refer to the Questions and Exercises section.
Guarded Blocks 保护块相关推荐
- linux dd命令参数及用法详解---用指定大小的块拷贝一个文件
linux dd命令使用详解 dd 的主要选项: 指定数字的地方若以下列字符结尾乘以相应的数字: b=512, c=1, k=1024, w=2, xm=number m if=file 输入文件名, ...
- Eclipse用法和技巧八:自动添加try/catch块1
站在编译器的角度来看,java中的异常可以分为两种,已检查异常和未检查异常.对于已检查异常比如IO操作,编译器会要求设置try/catch语句块,在eclipse中也只要使用帮助快捷键ctrl+1,就 ...
- JEP 378 Text blocks private interface methods
Java Versions and Features - HowToDoInJava Java 各版本和特性(Java Versions and Features) java 9 private in ...
- 转 ext文件系统及块组
一.文件系统概述 1. 引导块 前文中介绍过磁盘需要进行分区和格式化,才能创建文件系统并使用,那么一块已经被各式化了分区其结构是什么样的呢?分区是按照柱面来划分的,而柱面包含的是磁道,磁道上包含的是扇 ...
- icem 15.0中IJK control和blank blocks
之前进行点线面关联时一直先使用blocking-blocks右键blank blocks对块进行隐藏.最近有一次线关联错了,将关联错的块以外的块使用blank blocks隐藏,使用reset ass ...
- 【Linux】基础IO --- 内核级和用户级缓冲区、磁盘结构、磁盘的分治管理、block group块组剖析…
出身寒微,不是耻辱.能屈能伸,方为丈夫. 文章目录 一.缓冲区(语言级:IO流缓冲,内核级:块缓冲) 1.观察一个现象 2.理解缓冲区存在的意义(节省进程IO数据的时间) 3.语言级缓冲区的刷新策略( ...
- 代码保护软件 VMProtect 用户手册之准备项目: 使用标记
VMProtect 是一种很可靠的工具,可以保护应用程序代码免受分析和破解,但只有在应用程序内保护机制正确构建且没有可能破坏整个保护的严重错误的情况下,才能实现最好的效果 要保护代码的各 ...
- 多线程面试题_100多线程和Java并发面试问答–最终清单(PDF下载)
多线程面试题 在这篇文章中,我们将提供有关多线程和Java并发面试问答的综合文章. 编者注:并发始终是开发人员的挑战,编写并发程序可能非常困难. 引入并发时,有很多事情可能会崩溃,并且系统的复杂性会大 ...
- 4.6 W 字总结!Java 11—Java 17特性详解
作者 | 民工哥技术之路 来源 | https://mp.weixin.qq.com/s/SVleHYFQeePNT7q67UoL4Q Java 11 特性详解 基于嵌套的访问控制 与 Java 语言 ...
- Java并发教程(Oracle官方资料)
2019独角兽企业重金招聘Python工程师标准>>> 本文是Oracle官方的Java并发相关的教程,感谢并发编程网的翻译和投递. (关注ITeye官微,随时随地查看最新开发资讯. ...
最新文章
- 平衡二叉树-FHQ Treap(无旋平衡树)c/c++代码实现
- Apollo分布式配置中心在java的简单实现
- 形而上者谓之道,形而下者谓之器
- Python 代码便利并行,这个操作秀啊!
- MongoDB的高级语法
- antd vue 多个下拉 联动_Antd下拉选择,自动匹配功能的实现
- Volley学习总结
- 实验验证离散余弦变换和简单压缩应用,显示对应的原图,dct图和恢复的图像
- c++ 构造函数数组_“动态数组”的设计与实现
- 一本通1594涂抹果酱
- mysql导出数据到文件_MySQL导出数据到文件中
- 取消文件与svn服务器的关联
- 阿里大淘系模型治理方案分享
- 实验六 Linux下文件程序设计
- 解决office 2010每次启动都出现配置进度的方法
- 疫情影响之下,液晶面板价格上涨的期望或成空
- 雪の华 雪之华——不可不玩的好游戏(繁体中文版,附攻略、下载、歌词)...
- 嘉应学院计算机专业毕业好找工作吗,嘉应学院毕业证两字之差致学生求职碰壁...
- PHP拼团人数不能超过,怎么解决拼团、抽奖难以凑齐人数这个大问题?
- 译体验|Qualtrics:客户体验的六大法则