- 浏览: 888278 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
小宇宙_WZY:
膜拜一下大神,解决了我一个大问题,非常感谢 orz
【解惑】深入jar包:从jar包中读取资源文件 -
JKL852qaz:
感谢,遇到相同的问题!
【解惑】深入jar包:从jar包中读取资源文件 -
lgh1992314:
为什么java中调用final方法是用invokevirtua ...
【解惑】Java动态绑定机制的内幕 -
鲁曼1991:
说的都有道理,protected只能被同一级包的类所调用
【解惑】真正理解了protected的作用范围 -
鲁曼1991:
...
【总结】String in Java
对于初学者来说,下面这个例子是一个非常常见的错误。
/** * 线程A: 循环50次后等待并放弃锁,让线程B执行。 */ class ThreadA extends Thread{ //线程同步的公共数据区 Object oa=null; ThreadA(Object o){ this.oa=o; } //线程A执行逻辑 public void run(){ //线程同步区域,需要申请公共数据的锁 synchronized(oa){ System.out.println("ThreadA is running......"); for(int i=0;i<100;i++){ System.out.println(" ThreadA value is "+i); if(i==50){ try { //当前线程等待 Thread.currentThread().wait(); } catch (InterruptedException e) { e.printStackTrace(); } }//if(i==50) }//for(int i) } } } /** * 线程B:等待线程A放弃锁,然后获得锁并执行,完成后唤醒线程A */ class ThreadB extends Thread{ //线程同步的公共数据区 Object ob=null; ThreadB(Object o){ this.ob=o; } //线程B执行逻辑 public void run(){ //线程同步区域,需要申请公共数据的锁 synchronized(ob){ System.out.println("ThreadB is running......"); for(int i=0;i<50;i++){ System.out.println(" ThreadB value is "+i); } //唤醒等待的线程 notify(); } } } //测试 public class ThreadTest { public static void main(String[] args){ Object lock=new Object(); //公共数据区 ThreadA threada=new ThreadA(lock); ThreadB threadb=new ThreadB(lock); threada.start(); //线程A执行 threadb.start(); //线程B执行 } }
程序很简单,就是让线程A,B交替打印。但是运行的时候会抛出两个异常:
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException: current thread not owner
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException: current thread not owner
问题就处在ThreadA中的Thread.currentThread().wait(); 和ThreadB中的notify();上。
初学者理解wait()的时候都认为是将当前线程阻塞,所以Thread.currentThread().wairt();视乎很有道理。但是不知道大家有没有发现,在JDK类库中wait()和notify()方法并不是Thread类的,而是Object()中的。我们仔细看看wait方法的JDK文档:
public final void wait() throws InterruptedException
在其他线程调用此对象的 notify()
方法或 notifyAll()
方法前,当前线程等待。
换句话说,此方法的行为就好像它仅执行 wait(0)
调用一样。
当前线程必须拥有此
对象监视器
。该线程发布对此监视器的所有权并等待
,直到其他线程通过调用 notify
方法,或 notifyAll
方法通知在此对象的监视器上等待的线程醒来。
然后该线程将等到重新获得对监视器的所有权后才能继续执行。
对于某一个参数的版本,实现中断和虚假唤醒是可能的,而且此方法应始终在循环中使用:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
// Perform action appropriate to condition
}
此方法只应由作为此对象监视器的所有者的线程来调用。
抛出:
IllegalMonitorStateException
- 如果当前线程不是此对象监视器的所有者。
InterruptedException
- 如果在当前线程等待通知之前或者正在等待通知时,任何线程中断了当前线程。在抛出此异常时,当前线程的中断状态
被清除。
看完JDK文档以后,很显然,只要把开始的程序中Thread.currentThread().wait();改成oa.wait() 。 notify();改成 ob.notify()就没有问题了。
也就是说,只能通过同步块obj来调用wait/notify方法 ,而不能通过想当然的线程调用这两个方法。至于为什么是这样,我有一种想法,大家可以一起讨论一下:
首先,我们都知道JVM会给每一个对象都分配唯一的一把锁。这把锁是在对象中的。
然后,当Thread-0线程获得了这把锁后,应该是在对象中的锁内记录下当前占有自己的线程号,并把自己设置为已被占用。那么当Thread-0需要放弃锁的时候,锁对象会把 Thread-0放入到锁的等待队列中 。而这一切和Thread-0是没有任何关系的。自然也轮不到Thread-0对象来调用某个方法来改变另一个对象中的锁(这一点也说不通,我自己的锁凭什么让你来改)。
因此,也就出现用改变公共数据区对象的锁的方法是通过共数据区对象本省来调用,和线程对象是没有关系的。
事实上,每一个同步锁lock下面都挂了几个线程队列,包括就绪(Ready)队列,等待(Waiting)队列等。当线程A因为得不到同步锁lock,从而进入的是lock.ReadyQueue(就绪队列),一旦同步锁不被占用,JVM将自动运行就绪队列中的线程而不需要任何notify()的操作。但是当线程A被wait()了,那么将进入lock.WaitingQuene(等待队列),同时如果占据的同步锁也会放弃。而此时如果同步锁不唤醒等待队列中的进程(lock.notify()),这些进程将永远不会得到运行的机会。
就绪队列和等待队列有很大的不同,这一点要牢记。
对于object的wait、notify、notifyAll的理解,可以参见《Java 虚拟机体系结构 》中堆内存区的内容,就会有更加深刻的理解了。
评论
wait, notify操作首先保证当前线程持有锁。
对于上面我有不观点:notify就是从锁的等待队列里面选择第一个等待的线程进行调度。
我认为是是从锁的等待队列里面唤醒一个线程,唤醒哪个线程是不确定的或任意的;如果等待队列里面只有一个线程,那么就会唤醒这个线程。这里的唤醒与sleep并不是对等关系。唤醒之后的线程进入就绪队列,等待被选择执行。
我在多线程方面不熟,很多时候会犯低级错误。
不过oa,ob为什么是两个对象。奇怪了,他们引用的都是lock吗?这个我确定,不用再讨论了。
不过感谢大家的讨论,这个问题我现在清楚不少了,呵呵,谢谢
还有:我都两次被评新手帖了,这到没什么。主要问题是每次被评为新手帖JavaEye都要我回答一次破问卷,才能重新发帖。好烦哪?
JavaEye是不错的网站,但好东西是要简单的。规矩多了,不是好事
定义了一个synchronized 对象,意义上是把这个作为多线程之间的一把锁,
让线程wait,并不意味让这个对象wait
所以要释放正确的锁
这个观点比较认同,呵呵。 锁的是资源,不是线程类
定义了一个synchronized 对象,意义上是把这个作为多线程之间的一把锁,
让线程wait,并不意味让这个对象wait
所以要释放正确的锁
ThreadA threada=new ThreadA(lock);
ThreadB threadb=new ThreadB(lock);
怎么不是同一个监视器?明明就是嘛
而前两个对象的隐式锁并没有被任何的线程获得,synchronized的只是lock,两个线程竞争的都是lock的隐式锁.so,不管是wait()还是notify(),当前线程都不是其对应对象监视器的持有者,都会抛出上述的异常.
wait, notify操作首先保证当前线程持有锁。
锁确实是可重入的,线程能够重复获得它已经拥有的锁。而且锁对象会维护一个持有计数(hold count)来追踪对lock方法的嵌套调用。
there is only reentrant lock in java,
it means that there lock holder thread could acquire this lock again, then lock will increase his count (state+1) besides keeping lock's holder is current thread.
发表评论
-
NIO
2010-08-05 10:36 0在JDK1.4以前,I/O输入输出处理,我们把它称为旧 ... -
【总结】Java线程同步机制深刻阐述
2010-05-16 10:21 5934全文转载:http://www.iteye ... -
【JDK优化】java.util.Arrays的排序研究
2010-05-12 21:06 9112作者题记:JDK中有很多算法具有优化的闪光点,值得好好研究。 ... -
【JDK优化】 Integer 自动打包机制的优化
2010-03-12 19:14 4081我们首先来看一段代码: Integer i=100; In ... -
【总结】Java与字符编码问题详谈
2009-12-30 09:11 9349一、字符集和字符编码方式 计算机只懂得0/1两种信号 ... -
【解惑】JVM如何理解Java泛型类
2009-12-16 11:08 12226//泛型代码 public class Pair<T& ... -
【解惑】正确的理解this 和 super
2009-12-05 09:46 4415转载: 《无聊 ... -
【解惑】真正理解了protected的作用范围
2009-11-21 18:00 5004一提到访问控 ... -
【总结】String in Java
2009-11-21 17:52 10816作者:每次上网冲杯Java时,都能看到关于String无休无止 ... -
【解惑】真正理解了protected的作用范围
2009-11-16 17:11 585一提到访问控制符protected,即使是初学者 ... -
总结Java标准类库中类型相互转化的方法
2009-11-09 21:57 210组一: ☆ String → byte[ ... -
方法没覆盖住带来的烦恼
2009-11-05 09:18 100Object类是所有类的祖宗,它的equals方法比较的 ... -
【解惑】数组向上转型的陷阱
2009-11-03 11:44 1838问题提出: 有两个类Manager和Em ... -
【总结】java命令解析以及编译器,虚拟机如何定位类
2009-11-01 16:25 5750学Java有些日子了,一直都使用IDE来写程序。这 ... -
【解惑】剖析float型的内存存储和精度丢失问题
2009-10-26 15:10 15825问题提出:12.0f-11.9f=0.10 ... -
【解惑】领略内部类的“内部”
2009-10-19 15:38 3536内部类有两种情况: (1) 在类中定义一个类(私有内部类 ... -
【解惑】深入jar包:从jar包中读取资源文件
2009-10-08 21:13 65437我们常常在代码中读取一些资源文件(比如图片,音乐,文 ... -
【解惑】理解java枚举类型
2009-09-26 09:37 3356枚举类型是JDK5.0的新特征。Sun引进了一个全新的关键字e ... -
编写自己的equals方法
2009-09-20 14:18 129在我的《令人头疼的"相等"关 ... -
【解惑】Java类型间的转型
2009-09-11 16:03 5594★ 基本数据类型间的转换 1、Java要做到平台无关 ...
相关推荐
麦肯锡 组织 概述与基本框架gl.ppt
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
大型强子对撞机电源转换器设计与运行挑战
本文档提供了一套完整的STM32F411低功耗开发板资源,包含详细的原理图、PCB设计源文件、官方提供的示例程序以及必要的驱动程序。这些资料对于嵌入式系统开发者来说是宝贵的学习资源,特别适合那些希望深入了解STM32F411微控制器及其应用的学生、工程师和电子爱好者。文档旨在帮助用户快速上手STM32F411的开发工作,无论是进行学术研究、产品原型设计还是个人项目实践,都能从中获益。 关键词标签: STM32F411 低功耗 开发板 资料下载
该项目以发债企业作为研究对象,利用财务逻辑和技术手段对178个原始特征指标进行有效筛选,构建了基于多种机器学习算法的模型,对比后挑选LightGBM模型作为最终模型进行更精细化训练,最终模型关键预测指标均有比较好的效果。 使用说明 BondDefault文件为项目代码 基于机器学习的发债主体违约风险预测.pdf为pdf形式的项目文稿 基于机器学习的发债主体违约风险预测.pptx为ppt形式的项目展示 由于数据集太大,此处没有上传
Rain Birdt Simple To Set Timer (SST) 使用说明书
SITRANS LVL 200S, LVL 200E 振动式安全手册
麦肯锡-xx电信市场分析报告gl.ppt
基于matlab实现的三次样条插值法 求信号的包络线 源代码.rar
麦肯锡_xx大客户培训战略报告gl.ppt
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。
无人机最强算法源码,易于部署和学习交流使用
Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。