- 浏览: 1008050 次
- 性别:
- 来自: 广州
文章分类
- 全部博客 (394)
- OSGI (14)
- 多线程 (10)
- 数据库 (30)
- J2ME (1)
- JAVA基础知识 (46)
- 引用包 (1)
- 设计模式 (7)
- 工作流 (2)
- Ubuntu (7)
- 搜索引擎 (6)
- QT (2)
- Ubuntu下编程 (1)
- 小程序 (2)
- UML (1)
- Servlet (10)
- spring (16)
- IM (12)
- 文档视频转为flash格式在线播放 (19)
- Maven (8)
- 远程调用 (2)
- PHPRPC (1)
- EXTJS学习 (2)
- Hibernate (16)
- 技术文章 (38)
- flex (5)
- 海量数据处理 (5)
- FTP (8)
- JS (10)
- Struts (1)
- hibernate search (13)
- JQuery (2)
- EMail (3)
- 算法 (4)
- SVN (7)
- JFreeChart (4)
- 面试 (4)
- 正规表达式 (2)
- 数据库性能优化 (10)
- JVM (6)
- Http Session Cookie (7)
- 网络 (12)
- Hadoop (2)
- 性能 (1)
最新评论
-
hy1235366:
能够随便也发一下,你退火算法程序使用的DistanceMatr ...
模拟退火算法总结(含例子)(转) -
梅强强:
感谢分享。。帮大忙了
swftools转换文件时线程堵塞问题的解决方法 -
wenlongsust:
openoffice和文件不在同一个服务器上,用过吗?
[JODConverter]word转pdf心得分享(转) -
2047699523:
如何在java Web项目中开发WebService接口htt ...
利用Java编写简单的WebService实例 -
abingpow:
唉,看起来好像很详细很不错的样子,可惜不是篇面向初学者的文章, ...
Spring与OSGi的整合(二)(转)
问题
线程之间的关系是平等的,彼此之间并不存在任何依赖,它们各自竞争CPU资源,互不相让,并且还无条件地阻止其他线程对共享资源的异步访问。然而,也有很多现实问题要求不仅要同步的访问同一共享资源,而且线程间还彼此牵制,通过相互通信来向前推进。那么,多个线程之间是如何进行通信的呢?
解决思路
在现实应用中,很多时候都需要让多个线程按照一定的次序来访问共享资源,例如,经典的生产者和消费者问题。这类问题描述了这样一种情况,假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中的产品取走消费。如果仓库中没有产品,则生产者可以将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止。如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,直到仓库中再次放入产品为止。显然,这是一个同步问题,生产者和消费者共享同一资源,并且,生产者和消费者之间彼此依赖,互为条件向前推进。但是,该如何编写程序来解决这个问题呢?
传统的思路是利用循环检测的方式来实现,这种方式通过重复检查某一个特定条件是否成立来决定线程的推进顺序。比如,一旦生产者生产结束,它就继续利用循环检测来判断仓库中的产品是否被消费者消费,而消费者也是在消费结束后就会立即使用循环检测的方式来判断仓库中是否又放进产品。显然,这些操作是很耗费CPU资源的,不值得提倡。那么有没有更好的方法来解决这类问题呢?
首先,当线程在继续执行前需要等待一个条件方可继续执行时,仅有 synchronized 关键字是不够的。因为虽然synchronized关键字可以阻止并发更新同一个共享资源,实现了同步,但是它不能用来实现线程间的消息传递,也就是所谓的通信。而在处理此类问题的时候又必须遵循一种原则,即:对于生产者,在生产者没有生产之前,要通知消费者等待;在生产者生产之后,马上又通知消费者消费;对于消费者,在消费者消费之后,要通知生产者已经消费结束,需要继续生产新的产品以供消费。
其实,Java提供了3个非常重要的方法来巧妙地解决线程间的通信问题。这3个方法分别是:wait()、notify()和notifyAll()。它们都是Object类的最终方法,因此每一个类都默认拥有它们。
虽然所有的类都默认拥有这3个方法,但是只有在synchronized关键字作用的范围内,并且是同一个同步问题中搭配使用这3个方法时才有实际的意义。
这些方法在Object类中声明的语法格式如下所示:
final void wait() throws InterruptedException
final void notify()
final void notifyAll()
其中,调用wait()方法可以使调用该方法的线程释放共享资源的锁,然后从运行态退出,进入等待队列,直到被再次唤醒。而调用notify()方法可以唤醒等待队列中第一个等待同一共享资源的线程,并使该线程退出等待队列,进入可运行态。调用notifyAll()方法可以使所有正在等待队列中等待同一共享资源的线程从等待状态退出,进入可运行状态,此时,优先级最高的那个线程最先执行。显然,利用这些方法就不必再循环检测共享资源的状态,而是在需要的时候直接唤醒等待队列中的线程就可以了。这样不但节省了宝贵的CPU资源,也提高了程序的效率。
由于wait()方法在声明的时候被声明为抛出InterruptedException异常,因此,在调用wait()方法时,需要将它放入try…catch代码块中。此外,使用该方法时还需要把它放到一个同步代码段中,否则会出现如下异常:
"java.lang.IllegalMonitorStateException: current thread not owner"
这些方法是不是就可以实现线程间的通信了呢?下面将通过多线程同步的模型: 生产者和消费者问题来说明怎样通过程序解决多线程间的通信问题。
具体步骤
下面这个程序演示了多个线程之间进行通信的具体实现过程。程序中用到了4个类,其中ShareData类用来定义共享数据和同步方法。在同步方法中调用了wait()方法和notify()方法,并通过一个信号量来实现线程间的消息传递。
// 例4.6.1 CommunicationDemo.java 描述:生产者和消费者之间的消息传递过程
上面的例子是当还没有生产出产品时,消费者进入等待状态,而当产品生产出来后,就唤醒消费者,而当消费者还没有消费时,生产品就等待消费者消费后,再搞生产。 生产者和消费者线程在条件不满足的条件下交出CPU使用权,由操作系统将它们挂在等待队列,那它们在条件没够的情况下就不会有执行的机会,而不像用while来不停的判断条件是否满足,这样做,那么这两个线程在还是会占用CPU,就执行空操作,就是占着坑,不...的一样,浪费CPU宝贵资源,所以使用wait和notify会提高多线程环境下的CPU利用率。package chenwenbiao.test;
class ShareData
{
private char c;
private boolean isProduced = false; // 信号量
public synchronized void putShareChar(char c) // 同步方法putShareChar()
{
if (isProduced) // 如果产品还未消费,则生产者等待
{
try
{
wait(); // 生产者等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.c = c;
isProduced = true; // 标记已经生产
notify(); // 通知消费者已经生产,可以消费。调用它的隐藏方法notify
}
public synchronized char getShareChar() // 同步方法getShareChar()
{
if (!isProduced) // 如果产品还未生产,则消费者等待
{
try
{
wait(); // 消费者等待。调用它的隐藏方法wait
} catch (InterruptedException e) {
e.printStackTrace();
}
}
isProduced = false; // 标记已经消费
notify(); // 通知需要生产
return this.c;
}
}
class Producer extends Thread // 生产者线程
{
private ShareData s;
Producer(ShareData s)
{
this.s = s;
}
public void run()
{
for (char ch = 'A'; ch <= 'Z'; ch++)
{
try
{
Thread.sleep((int) (Math.random() * 3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
s.putShareChar(ch); // 将产品放入仓库
System.out.println(ch + " is produced by Producer.");
}
}
}
class Consumer extends Thread // 消费者线程
{
private ShareData s;
Consumer(ShareData s)
{
this.s = s;
}
public void run()
{
char ch;
do {
try
{
Thread.sleep((int) (Math.random() * 3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
ch = s.getShareChar(); // 从仓库中取出产品
System.out.println(ch + " is consumed by Consumer. ");
} while (ch != 'Z');
}
}
public class CommunicationDemo
{
public static void main(String[] args)
{
ShareData s = new ShareData();
new Consumer(s).start();
new Producer(s).start();
}
}
发表评论
-
Java线程(二):线程同步synchronized和volatile(转)
2014-03-17 00:09 914转载自:http://blog.csdn.net/ghsau ... -
浅谈Java多线程的同步问题(l转)
2014-03-17 00:07 955非常好的使用线程同步的文章 转载自http://www.c ... -
JVM的垃圾回收机制详解和调优(转)
2013-06-20 10:31 7401.JVM的gc概述 gc即垃圾 ... -
深入探讨 Java 类加载器(转)
2013-06-20 10:17 898转载自:http://www.ibm.com/develop ... -
java反射详解(推荐转)
2013-05-15 10:42 903载自:http://www.cnblogs.com/roll ... -
java静态方法、非静态代码块{}、静态代码块static{}(转)
2012-07-13 14:33 1511转自:http://www.cn-java.com/www1/ ... -
error 与 Exception区别(转)
2012-07-13 14:31 1100Error类和Exception类都继承自Throwab ... -
java面试题有哪些常见的(转)
2012-07-13 14:30 1219第一,谈谈final, finally, finaliz ... -
java Math.round()(转)
2012-07-11 14:17 1210public class MathTest { ... -
Java异常的分类(转)
2012-07-11 08:57 1067转载自:http://blog.csdn.net/ilibab ... -
java 内联函数(转)
2012-06-28 23:40 1850以前用过C++,知道它 ... -
堆栈,堆栈,堆和栈的区别(转)
2011-05-08 00:36 1209不防看看这篇文章:http://www.cppblog.com ... -
第二十章 指针 二 为指针分配和释放空间(转)
2011-05-08 00:10 1517载自<白话c++>:http://17de.com ... -
数据结构中各种时间复杂度(转)
2011-05-06 09:58 2812(1)冒泡排序 冒泡排序就是把小的元素往 ... -
C#之int挑战Java之Integer(转)
2011-04-28 14:24 1361可能有些图会看不到,可以到转载处去阅读:http://kb.c ... -
Java: 堆 & 栈(转)
2011-04-28 14:16 1420栈是运行时的单位,而堆是存储的单位。栈解决程序的运行问题,即程 ... -
native2ascii 使用方法 及 Java字符编码(转)
2011-04-18 01:17 2754在做Java开发的时候,常 ... -
Unicode,ISO-8859,GBK,UTF-8编码及相互转换(java)(转)
2011-04-18 01:15 69101、函数介绍在Java中,字符串用统一的Unicode编码 ... -
GBK与UTF-8 转换乱码详解(转)
2011-04-18 01:07 3508getBytes 的功能是将字符转换成字节数组, gbk. ... -
Java TreeMap的简单实现(转)
2011-04-18 00:29 1119TreeMap的实现与二叉搜索树显示,其对应的节点格式为 E ...
相关推荐
"Java多线程通信机制研究" Java多线程通信机制是Java程序设计中的一个复杂技术,涉及到多个线程之间的通信和协作。多线程是一种程序运行机制,它允许在程序中并发执行多个指令流,每个指令流都被称为一个线程,彼此...
一张图方便理解和掌握java 多线程之间通信的实质 java 多线程 其实就是每个线程都拥有自己的内存空间,多线程之间的通信,比例A线程修改了主内存(main方法的线程)变量,需要把A线程修改的结果同步到主线程中,...
Java多线程机制是Java编程中至关重要的一部分,它允许程序同时执行多个任务,提升应用程序的效率和响应性。以下是对各个知识点的详细说明: 9.1 Java中的线程: Java程序中的线程是在操作系统级别的线程基础上进行...
其中,wait()和notify()方法是Java语言中实现多线程通信和等待机制的两个核心方法。 wait()方法是Object类的一个方法,用来将当前线程置入“预执行队列”中,并且在wait()所在的代码行处停止执行,直到接到通知或被...
本案例将深入探讨Java多线程中的关键知识点,包括线程同步、线程通信和线程阻塞。 线程同步是为了防止多个线程同时访问共享资源,导致数据不一致。Java提供了多种同步机制,如synchronized关键字、Lock接口...
Java的多线程机制是Java语言的一大特性,它允许程序同时执行多个任务,提升程序响应速度,优化资源利用率。在Java中,线程是程序执行的最小单位,一个进程可以包含多个线程,每个线程都有自己独立的生命周期,包括...
Java多线程是Java编程语言中一个非常重要的概念,它允许开发者在一个程序中创建多个执行线程并行运行,以提高程序的执行效率和响应速度。在Java中,线程的生命周期包含五个基本状态,分别是新建状态(New)、就绪...
Java多线程是Java编程中的重要概念,尤其在如今的多核处理器环境下,理解并熟练掌握多线程技术对于提高程序性能和响应速度至关重要。本资料详细讲解了Java多线程的原理,并提供了丰富的实战代码,非常适合Java初学者...
Java多线程是Java编程中的一个重要概念,它允许程序同时执行多个任务,提高了程序的效率和响应速度。在Java中,实现多线程有两种主要方式:继承Thread类和实现Runnable接口。 1. 继承Thread类: 当我们创建一个新...
在本文中,我们将深入浅出Java多线程编程的世界,探索多线程编程的基本概念、多线程编程的优点、多线程编程的缺点、多线程编程的应用场景、多线程编程的实现方法等内容。 一、多线程编程的基本概念 多线程编程是指...
本文将深入探讨Java多线程机制,包括线程的创建、同步、通信以及常见设计模式。 首先,Java中创建线程主要有两种方式:通过实现Runnable接口和继承Thread类。实现Runnable接口更灵活,因为Java是单继承的,而通过...
Java多线程允许程序同时执行多个独立的代码段,这在处理大数据、网络通信、用户界面更新等场景中尤其有用。书中详细介绍了Java多线程的核心概念,如线程的创建、启动、同步、协作以及生命周期管理。读者将学习如何...
《JAVA多线程教学演示系统》是一篇深入探讨JAVA多线程编程的论文,它针对教育领域中的教学需求,提供了一种生动、直观的演示方式,帮助学生更好地理解和掌握多线程技术。这篇论文的核心内容可能包括以下几个方面: ...
总结起来,“JAVA多线程编程技术PDF”涵盖了多线程的基本概念、同步机制、线程通信、死锁避免、线程池以及线程安全的集合类等内容。通过深入学习这份资料,开发者可以全面掌握Java多线程编程技术,提升程序的并发...
在Java编程中,多线程并发是...总之,Java的多线程并发实例可以帮助我们更好地理解和实践线程控制、同步机制以及经典的设计模式,提升我们的编程能力。通过不断学习和实践,我们可以编写出高效、安全的多线程并发程序。
总的来说,Java多线程通信是一个复杂而重要的主题,涉及并发控制、线程安全、同步机制等多个方面。通过深入理解并熟练运用这些知识,开发者可以构建出高效、可靠的服务器多线程应用程序。在实际操作中,不断实践和...
Java多线程编程是Java开发中的重要组成部分,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,多线程主要通过继承Thread类或实现Runnable接口来实现。本教程《Java多线程编程核心技术》将...
《Java多线程编程实战指南》这本书深入浅出地讲解了Java多线程的核心概念和实战技巧,分为核心篇和设计模式篇,旨在帮助开发者掌握并应用多线程技术。 1. **线程基础** - **线程的创建**:Java提供了两种创建线程...