java 锁3
先谈线程的状态:
具体来说有,
NEW、
Running、
Blocked、此状态的线程阻塞,它正在等待监视器锁——等待另外一个线程释放锁(通俗说就是等它执行完synchronized了的方法/代码块)。 就是说出现了资源争用的情况。引起Blocked的原因,不用说,现在很明了了: 多个线程想同时进入同一个同步代码块——第一个进入的自然不会Blocked,后面的就Blocked。。 同步代码块 的实现就不说了,一般就是synchronized、Lock。。
Waiting、此状态的线程阻塞,它其实是在等待唤醒,就是重新获得锁(再通俗一点说就是获得失去过的。。。),引起Waiting的原因,就是由于调用了obj.wait导致失去了锁。。。 还有其他的吗?还有的!!:
- 不带超时值的
Object.wait
- 不带超时值的
Thread.join
LockSupport.park
好吧,join、park之流具体为什么导致线程的wait就不说了,太复杂,搞不懂了。。。
TIMED_WAITING、基本同上? no, 虽然和上面的状态都有wait,但是引起线程TIMED_WAITING的原因却大不相同!
一般来说,TIMED_WAITING原因有:
sleep
LockSupport.parkNanos
wait(time) ?
举例:
"main" prio= tid=0x0239c800 nid=0x3714 waiting on condition [0x01e7f000..0x01e7fe28]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at test.ObjectLock.main(ObjectLock.java:) "RMI TCP Connection(idle)" daemon prio= tid=0x0515fc00 nid=0x2d10 waiting on condition [0x0574f000..0x0574fc68]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x22ed03f8> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:)
at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:)
at java.lang.Thread.run(Thread.java:) "RMI TCP Connection(6)-10.0.0.23" daemon prio= tid=0x051b0400 nid=0x4d74 in Object.wait() [0x058fe000..0x058ffae8]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x22eee320> (a com.sun.jmx.remote.internal.ArrayNotificationBuffer)
at com.sun.jmx.remote.internal.ArrayNotificationBuffer.fetchNotifications(ArrayNotificationBuffer.java:)
- locked <0x22eee320> (a com.sun.jmx.remote.internal.ArrayNotificationBuffer)
at com.sun.jmx.remote.internal.ArrayNotificationBuffer$ShareBuffer.fetchNotifications(ArrayNotificationBuffer.ja
va:)
at com.sun.jmx.remote.internal.ServerNotifForwarder.fetchNotifs(ServerNotifForwarder.java:)
at javax.management.remote.rmi.RMIConnectionImpl$.run(RMIConnectionImpl.java:)
at javax.management.remote.rmi.RMIConnectionImpl$.run(RMIConnectionImpl.java:)
at javax.management.remote.rmi.RMIConnectionImpl.fetchNotifications(RMIConnectionImpl.java:)
TERMINATED 这个就不说了。原因? 线程执行完了,run方法执行完了,或者被close ?
关键是Blocked和Waiting的区别,
同:他们都导致了线程的阻塞(虽然说Blocked就是阻塞的意思,但是Waiting也是属于广义的阻塞),导致了线程不能继续执行,“卡住”了。
异:解除Blocked需要的是获得对象的锁,具体来说是synchronized或Lock所在方法/代码块对应的对象。 而解除Waiting需要执行wait方法的对象再次执行notify/notifyAll。
关联:两者其实可以理解为java提供的两种机制。 用法不同。
关键点:
1 锁,在java中是一直实实在在的对象,虽然但单从synchronized看不出哪里有new一个锁,但是java的底层机制确实是new了锁?并且关联在对应的线程之上。同时java还存在锁池的说法。而Lock, 则是显而易见了的new了锁。当然,两者的锁有所不同。
2 这里的对象,其实可以理解为一种资源。
3 wait、notify虽然不是直接的锁,但是和锁有千丝万缕的联系。 notify 可以唤醒等待在某对象的线程(亦即获得某对象的监视器)
4 不明白的是为什么wait、notify的时候一定需要synchronized等用获得对应的锁
5 对象的锁和对象的监视器 到底是什么概念, 怎么区分?
参考
http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.State.html
http://www.cnblogs.com/lostyue/archive/2012/03/21/2410793.html
Object 有提供 三个重构的wait、一个notify、一个notifAll 。 都是线程或者说多线程,相关的。
Wait()方法,使当前获得指定对象锁的线程阻塞并释放锁。 ————我很好奇,为什么要阻塞,然后又释放呢?
http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#wait()
我明白了,其实这是一种奇怪的机制,
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
synchronized(obj)等锁表明,使得线程执行时, 必须获得obj的锁。obj.wait()使得当期线程失去了锁(或者说释放了锁)。—— 既然释放了锁,而是synchronized又表明线程是需要锁的,—— 这样就导致了线程的阻塞—— 处于Waiting状态。—— 这种的阻塞的原因不同于不同线程同时进入synchronized方法/代码块引起的阻塞,Waiting—— 此时obj对象上应该是没有任何的监视器(或者说‘锁’),因为它之前获得过,失去的原因是它主动释放的锁。想要‘失去’得先‘有’才行——这样的机制使得synchronized有了存在性!!!!!!!!!
Blocked——此时obj对象上应该是有且只有一个监视器(一个对象不能有多个监视器吧。。)
—— 就是这样!!
—— 既然如此,Waiting状态的线程对那个对象已经没有了监视器,是否可以被别的线程获得此对象监视器呢,然后导致该线程对obj执行notify失败? 可以这样!但是java规定notify的时候一定需要synchronized,不允许这种情况出现,也永远不会出现——这就解释了notify的时候一定需要synchronized等用获得对应的锁!!!!!!!!!!!!!!
Notify、NotifyAll 使当前没有获得指定对象锁的线程唤醒。
http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#notify()
Notify的困惑之处在于,它是随机唤醒等待在该对象上的线程的,当然,如果只有一个线程等待,不会有随机的说法。
为什么是‘随机’呢???
方法调用一定要处于synchronized关键字包含的代码中,即锁控制的区域。
package test; public class ObjectLock { public static void main(String[] args) { final SimpleBean bean = new SimpleBean();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
bean.aa();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
bean.bb();
}
}); t1.start();
try {
Thread.sleep();// sleep1
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start(); } } class SimpleBean { public synchronized void aa() {
System.out.println("SimpleBean.aa() start !");
try {
this.wait();//----------- 这里的wait并没有处于loop-condition之中, 这样写法有问题吗????
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("SimpleBean.aa() end !");
} public synchronized void bb() {
System.out.println("SimpleBean.bb() 1");
this.notify();
System.out.println("SimpleBean.bb() 2");
} } 打印:
SimpleBean.aa() start !
SimpleBean.bb()
SimpleBean.bb()
SimpleBean.aa() end ! 新建线程的sleep1时候的堆栈:
"Thread-0" prio=6 tid=0x02334400 nid=0x35fc in Object.wait() [0x047bf000..0x047bfb68]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x22e74c10> (a test.SimpleBean)
at java.lang.Object.wait(Object.java:485)
at test.SimpleBean.aa(ObjectLock.java:41)
- locked <0x22e74c10> (a test.SimpleBean)
at test.ObjectLock$1.run(ObjectLock.java:13)
at java.lang.Thread.run(Thread.java:619)
名称: Thread-0
状态:WAITING 在 test.SimpleBean@1f4cbee 上
阻塞总数:0 等待总数: 1
堆栈追踪:
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:485)
test.SimpleBean.aa(ObjectLock.java:41)
test.ObjectLock$1.run(ObjectLock.java:13)
java.lang.Thread.run(Thread.java:619)
注:
wait抛出非runtime Exception, 必须捕获; notify 则不是。
wait、notify都必须被处于锁控制的区域,即一定要处于synchronized关键字或Lock的锁,包含的代码中。 否则就是 java.lang.IllegalMonitorStateException
参考 http://www.cnblogs.com/xwdreamer/archive/2012/05/12/2496843.html
奇怪的是这么一句: 即使你确实知道当前上下文线程确实拥有了对象锁,也不能将object.wait()这样的语句写在当前上下文中
如果改成这样:
package test; public class ObjectLock { public static void main(String[] args) { final SimpleBean bean = new SimpleBean();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
bean.aa();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
bean.bb();
}
}); t1.start();
// try {
// Thread.sleep(100000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
t2.start(); } } class SimpleBean { public synchronized void aa() {
System.out.println("SimpleBean.aa() start !");
try {
// this.wait();
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("SimpleBean.aa() end !");
} public synchronized void bb() {
System.out.println("SimpleBean.bb() 1");
this.notify();
System.out.println("SimpleBean.bb() 2");
} }
则
"Thread-1" prio=6 tid=0x02283000 nid=0x2be4 waiting for monitor entry [0x0483f000..0x0483fce8]
java.lang.Thread.State: BLOCKED (on object monitor)
at test.SimpleBean.bb(ObjectLock.java:50)
- waiting to lock <0x229bdde8> (a test.SimpleBean)
at test.ObjectLock$2.run(ObjectLock.java:19)
at java.lang.Thread.run(Thread.java:619)
"Thread-0" prio=6 tid=0x02280c00 nid=0x3a7c waiting on condition [0x047af000..0x047afd68]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at test.SimpleBean.aa(ObjectLock.java:42)
- locked <0x229bdde8> (a test.SimpleBean)
at test.ObjectLock$1.run(ObjectLock.java:13)
at java.lang.Thread.run(Thread.java:619)
名称: Thread-0
状态: TIMED_WAITING
阻塞总数:0 等待总数: 1
堆栈追踪:
java.lang.Thread.sleep(Native Method)
test.SimpleBean.aa(ObjectLock.java:42)
- 已锁定 test.SimpleBean@d72200
test.ObjectLock$1.run(ObjectLock.java:13)
java.lang.Thread.run(Thread.java:619)
名称: Thread-1
状态:BLOCKED 在 test.SimpleBean@d72200 上,拥有者: Thread-0
阻塞总数:1 等待总数: 0
堆栈追踪:
test.SimpleBean.bb(ObjectLock.java:50)
test.ObjectLock$2.run(ObjectLock.java:19)
java.lang.Thread.run(Thread.java:619)
可以看到Wait 方法确实是释放了锁的? 使外层的synchronized失效?
释放对象监控器的所有权,直到另外一个线程通过notify或notifyAll来唤醒。。。
<br>wait() <br>JDk文档写道 <br><br>在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。换句话说,此方法的行为就好像它仅执行 wait(0) 调用一样。 <br><span style="">当前线程必须拥有此对象监视器</span> 。该线程发布对此监视器的所有权并等待,直到其他线程通过调用 notify 方法,或 notifyAll 方法通知在此对象的监视器上等待的线程醒来。然后该线程将等到重新获得对监视器的所有权后才能继续执行。
而且此方法应始终在循环中使用 ??
参考:http://www.360doc.com/content/12/1010/19/59141_240697086.shtml
好难理解。。
http://blog.sina.com.cn/s/blog_5ffe533a0101iw25.html
wait、notify 等和synchronized的关系?
重点:
Object的wait、notify等方法是为了多线程之间协作而准备的!明白了这点,就不会有那么多纠结了吧.. !!
2 Thread的sleep、interrupt、suspend、close。。。
java 锁3的更多相关文章
- java 锁!
问题:如何实现死锁. 关键: 1 两个线程ta.tb 2 两个对象a.b 3 ta拥有a的锁,同时在这个锁定的过程中,需要b的锁:tb拥有b的锁,同时在这个锁定的过程中,需要a的锁: 关键的实现难点是 ...
- Java锁(一)之内存模型
想要了解Java锁机制.引发的线程安全问题以及数据一致性问题,有必要了解内存模型,机理机制了解清楚了,这些问题也就应声而解了. 一.主内存和工作内存 Java内存模型分为主内存和工作内存,所有的变量都 ...
- Java锁的种类
转载自:---->http://ifeve.com/java_lock_see/ Java锁的种类以及辨析锁作为并发共享数据,保证一致性的工具,在JAVA平台有多种实现(如 synchroniz ...
- JAVA 锁
JAVA 锁 锁的概念 Java中的锁是控制资源访问的一种方式.它弥补了synchronized的可操作性不强的不足. Java的锁都实现了Lock接口.Lock结构定义了锁的基本操作. 函数 解释 ...
- JAVA锁的可重入性
机制:每个锁都关联一个请求计数器和一个占有他的线程,当请求计数器为0时,这个锁可以被认为是unhled的,当一个线程请求一个unheld的锁时,JVM记录锁的拥有者,并把锁的请求计数加1,如果同一个线 ...
- JAVA 锁之 Synchronied
■ Java 锁 1. 锁的内存语义 锁可以让临界区互斥执行,还可以让释放锁的线程向同一个锁的线程发送消息 锁的释放要遵循 Happens-before 原则(锁规则:解锁必然发生在随后的加锁之前) ...
- java锁与监视器概念 为什么wait、notify、notifyAll定义在Object中 多线程中篇(九)
在Java中,与线程通信相关的几个方法,是定义在Object中的,大家都知道Object是Java中所有类的超类 在Java中,所有的类都是Object,借助于一个统一的形式Object,显然在有些处 ...
- 自己动手写java锁
1.LockSupport的park和unpark方法的基本使用,以及对线程中断的响应性 LockSupport是JDK中比较底层的类,用来创建锁和其他同步工具类的基本线程阻塞原语.java锁和同步器 ...
- Java 锁的学习
个人学习整理,所有资料均来源于网络,非原创. 死锁的四个必要条件:互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用.请求与保持条件(Hold and wait):已经得 ...
- java锁——wait,notify,synchronized
背景:这篇博客用来总结java锁相关的知识点,平时还是要自己多加练习 wait 和 notify以及notifyAll (1).方法介绍1.wait.notify以及notifyAll都是Object ...
随机推荐
- C# Form.Close 的释放问题
今天使用From窗口Close后,发现From的资源还存在,并没有释放资源,只有在程序关闭的时候才去释放. Form1:button按钮 private void button1_Click(obje ...
- OD使用教程8
方式一基本的打补丁方式: 打开程序之后首先会跳出一个nag窗口,从中我们知道了可以将nag窗口作为切入点,只要找到了nag的触发点就等同于找到注册与未注册的判断的点 右键-查找-所有参考文本字串 ...
- oracle后台进程详解
oracle后台进程伴随实例的启动而启动,他们主要是维护数据库的稳定,相当于一个企业中的管理者及内部服务人员.他们并不会直接给用户提供服务. 一:database write--数据写入 DBW ...
- PHP-Mysqli扩展库的预编译
(1)预编译的好处 假如要执行100条类似的sql语句,每一次执行,在MySQL端都会进行一次编译,效率很低.提高效率的方法就是--减少编译的次数. 先制造一个sql语句的模板,在MySQL端预先编译 ...
- 『TCP/IP详解——卷一:协议』读书笔记——11
2013-08-23 20:00:18 第4章 ARP:地址解析协议 4.1 引言 ARP(Address Resolution Protocol,地址解析协议)是获取物理地址的一个TCP/IP协议. ...
- vs2013的安装以及单元测试
一.安装过程 1.下载vs2013安装包,打开进行安装.安装过程时间有点长,大概用了一个小时. 2.安装完成.需要登录,可以选择以后再说. 3.选择颜色主题. 4.打开vs2013的界面. 5.添加密 ...
- Redux-Form学习笔记
总结下使用Redux-Form的步骤,基本的Form使用我分为一下5步: 安装Redux-Form npm install --save redux-form 创建reducer import {re ...
- [Leetcode][JAVA] Path Sum I && II
Path Sum Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that addi ...
- ubuntu下面mysql,通过载入txt文件初始化数据表
环境:ubuntu12.04 mysql(通过apt安装) (1)根据数据表中的属性列,对应在txt中构造记录(一行对应一条记录),不同属性之间通过tab键(以/root目录下构建的init.tx ...
- 【转】【WebDriver】不可编辑域和日历控件域的输入 javascript
http://blog.csdn.net/fudax/article/details/8089404 今天用到日历控件,用第一个javascript执行后页面上的日期控件后,在html中可以看到生效日 ...