- 浏览: 88473 次
- 性别:
- 来自: 深圳
最新评论
-
spdx4046:
我发现用数组和不用数组的差别很大很大哎!
比如: ...
Java NIO ByteBuffer -
comeonbabye:
楼主的确是心情不畅,导致思维缓慢。
类似的经历我也有过。哪天 ...
一次失败的面试 -
yysct2005:
解释:
功能权限:能做什么的问题,如增加销售订单;
数据权 ...
权限系统设计 -
yysct2005:
1、权限模型本质要素分为三个:主体+动作+客体
------ ...
权限系统设计 -
kv0002:
虽然看得不是很懂,但一定要顶
转载 ---【译】构建可扩展的Java EE应用(二)
Java线程:线程的交互
SCJP5学习笔记
线程交互是比较复杂的问题,SCJP要求不很基础:给定一个场景,编写代码来恰当使用等待、通知和通知所有线程。
一、线程交互的基础知识
SCJP所要求的线程交互知识点需要从java.lang.Object的类的三个方法来学习:
void notify()
唤醒在此对象监视器上等待的单个线程。
void notifyAll()
唤醒在此对象监视器上等待的所有线程。
void wait()
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
唤醒在此对象监视器上等待的单个线程。
void notifyAll()
唤醒在此对象监视器上等待的所有线程。
void wait()
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
当然,wait()还有另外两个重载方法:
void wait(long timeout)
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。
void wait(long timeout, int nanos)
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。
void wait(long timeout, int nanos)
导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
以上这些方法是帮助线程传递线程关心的时间状态。
关于等待/通知,要记住的关键点是:
必须从同步环境内调用wait()、notify()、notifyAll()方法。线程不能调用对象上等待或通知的方法,除非它拥有那个对象的锁。
wait()、notify()、notifyAll()都是Object的实例方法。与每个对象具有锁一样,每个对象可以有一个线程列表,他们等待来自该信号(通知)。线程通过执行对象上的wait()方法获得这个等待列表。从那时候起,它不再执行任何其他指令,直到调用对象的notify()方法为止。如果多个线程在同一个对象上等待,则将只选择一个线程(不保证以何种顺序)继续执行。如果没有线程等待,则不采取任何特殊操作。
下面看个例子就明白了:
/**
* 计算输出其他线程锁计算的数据
*
* @author leizhimin 2008-9-15 13:20:38
*/
public class ThreadA {
public static void main(String[] args) {
ThreadB b = new ThreadB();
//启动计算线程
b.start();
//线程A拥有b对象上的锁。线程为了调用wait()或notify()方法,该线程必须是那个对象锁的拥有者
synchronized (b) {
try {
System.out.println("等待对象b完成计算。。。");
//当前线程A等待
b.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("b对象计算的总和是:" + b.total);
}
}
}
* 计算输出其他线程锁计算的数据
*
* @author leizhimin 2008-9-15 13:20:38
*/
public class ThreadA {
public static void main(String[] args) {
ThreadB b = new ThreadB();
//启动计算线程
b.start();
//线程A拥有b对象上的锁。线程为了调用wait()或notify()方法,该线程必须是那个对象锁的拥有者
synchronized (b) {
try {
System.out.println("等待对象b完成计算。。。");
//当前线程A等待
b.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("b对象计算的总和是:" + b.total);
}
}
}
/**
* 计算1+2+3 ... +100的和
*
* @author leizhimin 2008-9-15 13:20:49
*/
public class ThreadB extends Thread {
int total;
public void run() {
synchronized (this) {
for (int i = 0; i < 101; i++) {
total += i;
}
//(完成计算了)唤醒在此对象监视器上等待的单个线程,在本例中线程A被唤醒
notify();
}
}
}
* 计算1+2+3 ... +100的和
*
* @author leizhimin 2008-9-15 13:20:49
*/
public class ThreadB extends Thread {
int total;
public void run() {
synchronized (this) {
for (int i = 0; i < 101; i++) {
total += i;
}
//(完成计算了)唤醒在此对象监视器上等待的单个线程,在本例中线程A被唤醒
notify();
}
}
}
等待对象b完成计算。。。
b对象计算的总和是:5050
Process finished with exit code 0
b对象计算的总和是:5050
Process finished with exit code 0
千万注意:
当在对象上调用wait()方法时,执行该代码的线程立即放弃它在对象上的锁。然而调用notify()时,并不意味着这时线程会放弃其锁。如果线程荣然在完成同步代码,则线程在移出之前不会放弃锁。因此,只要调用notify()并不意味着这时该锁变得可用。
二、多个线程在等待一个对象锁时候使用notifyAll()
在多数情况下,最好通知等待某个对象的所有线程。如果这样做,可以在对象上使用notifyAll()让所有在此对象上等待的线程冲出等待区,返回到可运行状态。
下面给个例子:
/**
* 计算线程
*
* @author leizhimin 2008-9-20 11:15:46
*/
public class Calculator extends Thread {
int total;
public void run() {
synchronized (this) {
for (int i = 0; i < 101; i++) {
total += i;
}
}
//通知所有在此对象上等待的线程
notifyAll();
}
}
* 计算线程
*
* @author leizhimin 2008-9-20 11:15:46
*/
public class Calculator extends Thread {
int total;
public void run() {
synchronized (this) {
for (int i = 0; i < 101; i++) {
total += i;
}
}
//通知所有在此对象上等待的线程
notifyAll();
}
}
/**
* 获取计算结果并输出
*
* @author leizhimin 2008-9-20 11:15:22
*/
public class ReaderResult extends Thread {
Calculator c;
public ReaderResult(Calculator c) {
this.c = c;
}
public void run() {
synchronized (c) {
try {
System.out.println(Thread.currentThread() + "等待计算结果。。。");
c.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "计算结果为:" + c.total);
}
}
public static void main(String[] args) {
Calculator calculator = new Calculator();
//启动三个线程,分别获取计算结果
new ReaderResult(calculator).start();
new ReaderResult(calculator).start();
new ReaderResult(calculator).start();
//启动计算线程
calculator.start();
}
}
* 获取计算结果并输出
*
* @author leizhimin 2008-9-20 11:15:22
*/
public class ReaderResult extends Thread {
Calculator c;
public ReaderResult(Calculator c) {
this.c = c;
}
public void run() {
synchronized (c) {
try {
System.out.println(Thread.currentThread() + "等待计算结果。。。");
c.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "计算结果为:" + c.total);
}
}
public static void main(String[] args) {
Calculator calculator = new Calculator();
//启动三个线程,分别获取计算结果
new ReaderResult(calculator).start();
new ReaderResult(calculator).start();
new ReaderResult(calculator).start();
//启动计算线程
calculator.start();
}
}
运行结果:
Thread[Thread-1,5,main]等待计算结果。。。
Thread[Thread-2,5,main]等待计算结果。。。
Thread[Thread-3,5,main]等待计算结果。。。
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException: current thread not owner
at java.lang.Object.notifyAll(Native Method)
at threadtest.Calculator.run(Calculator.java:18)
Thread[Thread-1,5,main]计算结果为:5050
Thread[Thread-2,5,main]计算结果为:5050
Thread[Thread-3,5,main]计算结果为:5050
Process finished with exit code 0
Thread[Thread-2,5,main]等待计算结果。。。
Thread[Thread-3,5,main]等待计算结果。。。
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException: current thread not owner
at java.lang.Object.notifyAll(Native Method)
at threadtest.Calculator.run(Calculator.java:18)
Thread[Thread-1,5,main]计算结果为:5050
Thread[Thread-2,5,main]计算结果为:5050
Thread[Thread-3,5,main]计算结果为:5050
Process finished with exit code 0
运行结果表明,程序中有异常,并且多次运行结果可能有多种输出结果。这就是说明,这个多线程的交互程序还存在问题。究竟是出了什么问题,需要深入的分析和思考,下面将做具体分析。
实际上,上面这个代码中,我们期望的是读取结果的线程在计算线程调用notifyAll()之前等待即可。 但是,如果计算线程先执行,并在读取结果线程等待之前调用了notify()方法,那么又会发生什么呢?这种情况是可能发生的。因为无法保证线程的不同部分将按照什么顺序来执行。幸运的是当读取线程运行时,它只能马上进入等待状态----它没有做任何事情来检查等待的事件是否已经发生。 ----因此,如果计算线程已经调用了notifyAll()方法,那么它就不会再次调用notifyAll(),----并且等待的读取线程将永远保持等待。这当然是开发者所不愿意看到的问题。
因此,当等待的事件发生时,需要能够检查notifyAll()通知事件是否已经发生。
通常,解决上面问题的最佳方式是将
本文出自 “熔 岩” 博客,转载请与作者联系!
本文出自 51CTO.COM技术博客发表评论
-
Java NIO编程关注点
2011-12-02 18:01 1149阅读yanf4j源码对于read事件、write事件的笔记 ... -
Java NIO ByteBuffer
2011-12-02 17:39 1174在 NIO 库中,所有 ... -
MINA ByteBuffer熟悉
2011-12-02 15:43 1558前不久,一个客户使用MINA架构服务器,在与客户端通信时, ... -
网络编程TCP通信的粘包问题讨论
2011-11-16 18:43 3397第一个需要讨论的大 ... -
多线程设计要点
2009-11-27 15:28 7401.多线程中有主内存和工作内存之分, 在JVM中,有一个主内存 ... -
Java线程:新特征-障碍器
2009-11-27 15:25 730Java线程:新特征-障碍器 Java5中,添加了 ... -
Java线程:新特征-原子量
2009-11-27 15:24 732Java线程:新特征-原子量 所谓的原子量即操作变 ... -
Java线程:新特征-条件变量
2009-11-27 15:23 834Java线程:新特征-条件变量 条件变量是Java ... -
Java线程:新特征-阻塞栈
2009-11-27 15:20 709Java线程:新特征-阻塞 ... -
Java线程:新特征-阻塞队列
2009-11-27 15:20 844阻塞队列是Java5线程新 ... -
Java线程:新特征-信号量
2009-11-27 15:18 833Java线程:新特征-信号量 Java的信号量实际上是 ... -
Java线程:新特征-锁(下)
2009-11-27 15:13 727Java线程:新特征-锁(下) 在上文中提到了L ... -
Java线程:新特征-锁(上)
2009-11-27 15:13 700在Java5中,专门提供了锁对象,利用锁可以方便的实现资源的封 ... -
Java线程:新特征-有返回值的线程
2009-11-27 14:42 876Java线程:新特征-有返回值的线程 在Ja ... -
Java线程:新特征-线程池
2009-11-27 14:40 909Sun在Java5中,对Java线程的类库做了大量的扩展,其中 ... -
Java线程:volatile关键字
2009-11-27 14:35 612Java线程:volatile关键字 Java™ ... -
Java线程:并发协作-死锁
2009-11-27 14:33 638Java线程:并发协作-死锁 线程发生死锁可 ... -
Java线程:并发协作-生产者消费者模型
2009-11-27 14:31 875Java线程:并发协作-生产者消费者模型 对于多线 ... -
Java线程:线程的同步-同步块
2009-11-27 14:30 926Java线程:线程的同步-同步块 对于同步,除了同 ... -
Java线程:线程的调度-守护线程
2009-11-27 14:27 854Java线程:线程的调度-守护线程 守护线程与普通 ...
相关推荐
Java线程:线程的交互 Java线程:线程的调度-休眠 Java线程:线程的调度-优先级 Java线程:线程的调度-让步 Java线程:线程的调度-合并 Java线程:线程的调度-守护线程 Java线程:线程的同步-同步方法 Java线程:...
Java线程:线程的交互 Java线程:线程的调度-休眠 Java线程:线程的调度-优先级 Java线程:线程的调度-让步 Java线程:线程的调度-合并 Java线程:线程的调度-守护线程 Java线程:线程的同步-同步方法 Java...
Java线程:概念与原理 2 一、操作系统中线程和进程的概念 2 ...Java线程:并发协作-线程的交互 47 Java线程:并发协作-生产者消费者模型 52 Java线程:并发协作-死锁 55 Java线程:线程之间的数据传递 58
Java线程:线程的交互 Java线程:线程的调度-休眠 Java线程:线程的调度-优先级 Java线程:线程的调度-让步 Java线程:线程的调度-合并 Java线程:线程的调度-守护线程 Java线程:线程的同步-同步方法 Java线程:...
Java线程:线程的交互 Java线程:线程的调度-休眠 Java线程:volatile关键字 Java线程:新特征-线程池 一、固定大小的线程池 二、单任务线程池 三、可变尺寸的线程池 四、延迟连接池 五、单任务延迟连接池 ...
创建和启动Java线程: * 可以使用extends Thread方法创建线程。 * 可以使用Runnable接口创建线程。 线程的状态和线程控制: * 线程的状态包括新建、可运行、阻塞、等待、死亡等。 * 线程控制包括线程的启动、暂停...
java编写的多线程交互示例程序,轻松理解java线程同步。
Java线程并发是一种复杂的技术,需要深入理解线程之间的交互、同步机制、死锁、饥饿、活锁等概念。以下是14个Java线程并发面试题和答案的详细解析: 1. 问题:java中的线程是什么? 答案:在Java中,线程是指一个...
包含java线程的概念、原理、交互、合并、让步、守护、休眠、同步、锁以及新特性 锁 线程池 信号量 有返回值的线程 原子量 障碍器 阻塞列队和阻塞栈。java开发必备参考文档。
Java 模拟线程死锁 线程死锁 在 Java 中,线程死锁(Deadlock)是一种特殊的情况,发生在两个或多个线程之间的互相等待对方释放资源的状态。这种情况下,各个线程都在等待其他线程释放资源,而自己也占用着其他...
本源代码是博客《Java 多线程编程之六:线程之间的通信(附源代码)》附带的实例性源代码。原博客链接地址:http://blog.csdn.net/defonds/archive/2010/01/26/5257301.aspx。
本文总结了JAVA多线程与并发的相关知识点,涵盖计算机系统的高速缓存机制、JAVA内存模型、内存间交互操作、volatile型变量、原子性、可见性与有序性、先行发生原则等内容。 计算机系统使用高速缓存来作为内存与...
java多线程的创建,主流的几种创建方式都有详细的讲解。线程的交互以及线程的同步锁的问题都有具体的实例。java的内存模型,java会话都有讲解,如果是刚接触java多线程,可以下载来看看
本书还附带光盘,光盘中包含用以辅助说明正文内容的交互式例示apple及示例源代码。 目录: 译者序 前言 第1章 java体系结构介绍 1.1 为什么使用java 1.2 网络带来的挑战和机遇 1.3 体系结构 1.3.1 java...
3.介绍线程并不是孤独的, 它们之间要通信, 要交互。 本章主要介绍waitO、 notify All()和notify()方法的使用, 使线程间能互相通信, 合作完成任务。 本章还介绍了Thread Local类的使用。 学习完本章, 读者就能在...
Java分布式应用学习笔记03JVM对线程的资源同步和交互机制
16:55:20.675 [main] INFO org.malin.allutils.makefile.ReadFileNameUtil - 获取到 文件名称: 10.并发调试和JDK8新特性.pdf 16:55:20.677 [main] INFO org.malin.allutils.makefile.ReadFileNameUtil - 获取到 ...
Java 多线程编程应用场景 —— 电影院售票系统设计 本资源摘要信息将对 Java 多线程编程在电影院售票系统设计中的应用进行详细介绍。该系统模拟了电影院三个售票窗口同时出售电影票的过程,通过 Java 多线程编程...