java 锁!
问题:如何实现死锁。
关键:
1 两个线程ta、tb
2 两个对象a、b
3 ta拥有a的锁,同时在这个锁定的过程中,需要b的锁;tb拥有b的锁,同时在这个锁定的过程中,需要a的锁;
关键的实现难点是3, —— 所以说,死锁也不是那么容易出现的吧。。
实现方式synchronized、Lock 等等
死锁例子1 采用了不同类的两个对象。 原理是: 两个线程尝试进入同一个需要对象锁的方法
package basic.thread; public class DL { public static void main(String[] args) {
dla a = new dla();
a.start(); dlb b = new dlb();
b.start();
}
} class dla extends Thread{ @Override
public void run() {
System.out.println("dla-------------");
Res.getInstace().aa();
}
} class dlb extends Thread{ @Override
public void run() {
System.out.println("dlb-----------");
Res2.getInstace().bb();
//super.run();
}
} class Res {
private static Res res = new Res();; public static Res getInstace() {
return res;
} private Res() { }
public synchronized void aa() {
System.out.println("Res.aa()");
try {
Thread.sleep();
Res2.getInstace().bb();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} class Res2 {
private static Res2 res = new Res2();; public static Res2 getInstace() {
return res;
} private Res2() { } public synchronized void bb() {
System.out.println("Res2.bb()");
try {
Thread.sleep();
Res.getInstace().aa();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
死锁例子2 原理是: 两个线程尝试进入同一个需要对象锁的方法。 这就说明的,只要是一个线程ta正在执行synchronized的方法ma(没有返回,这一点相当关键),下次别的线程进入同一个类的同一方法也好,别的synchronized方法也好,都是需要等待ta在ma的返回,就是要等ta在ma执行完了后才行,简单说就是不能进入。。—— 说起来好拗口。。。
package basic.thread; public class DL { public static void main(String[] args) {
dla a = new dla();
a.start(); dlb b = new dlb();
b.start();
}
} class dla extends Thread{ @Override
public void run() {
System.out.println("dla-------------");
Res.getInstace().aa();
}
} class dlb extends Thread{ @Override
public void run() {
System.out.println("dlb-----------");
Res2.getInstace().bb();
//super.run();
}
} class Res {
private static Res res = new Res();; public static Res getInstace() {
return res;
} private Res() { }
public synchronized void aa() {
System.out.println("Res.aa()");
try {
Thread.sleep();
Res2.getInstace().bbb();
} catch (InterruptedException e) {
e.printStackTrace();
}
} public synchronized void aaa() {
System.out.println("Res.aaa()");
}
} class Res2 {
private static Res2 res = new Res2();; public static Res2 getInstace() {
return res;
} private Res2() { } public synchronized void bb() {
System.out.println("Res2.bb() + " + Thread.currentThread().getName());
try {
Thread.sleep();
Res.getInstace().aaa();
} catch (InterruptedException e) {
e.printStackTrace();
}
} public synchronized void bbb() { System.out.println("Res2.bbb()");
}
}
死锁例子3 采用了同一个类的两个对象。(自旋锁? 这个例子相当不好,因为可能出现死循环! 看来还是两个不同类来实现死锁比较容易)
package basic.thread; public class DL {
public static void main(String[] args) {
Res res = new Res();
Res another = new Res();
res.setAnother(another);
another.setAnother(res);
dlb b1 = new dlb(res);
dlb b2 = new dlb(another);
b1.start();
b2.start();
}
} class dlb extends Thread{
Res res;
public dlb(Res res) {
this.res = res;
}
@Override
public void run() {
System.out.println("dlb-----------");
res.aa();
}
} class Res { Res another;
public void setAnother(Res another) {
this.another = another;
} public synchronized void aa() {
System.out.println("Res.aa()");
try {
Thread.sleep();
another.aa();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
lock trylock
上例中把 synchronized 改成lock,则发生死锁,一样的效果。但是改成trylock ,则不会发生死锁!
package basic.thread; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class DL { public static void main(String[] args) {
Res res = new Res();
Res another = new Res();
res.setAnother(another);
another.setAnother(res);
dlb b1 = new dlb(res);
dlb b2 = new dlb(another);
b1.start();
b2.start();
}
} class dlb extends Thread{
Res res;
public dlb(Res res) {
this.res = res;
}
@Override
public void run() {
System.out.println("dlb-----------");
res.aa();
}
} class Res { Res another;
public void setAnother(Res another) {
this.another = another;
}
ReentrantLock lock = new ReentrantLock(); public void aa() {
lock.lock();
System.out.println("Res.aa()");
try {
Thread.sleep();
another.aa();
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
} }
lock时候堆栈为:
"Thread-1" prio= tid=0x022eec00 nid=0x1e74 waiting on condition [0x0487f000..0x0487fae8]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x22e75958> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:
)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:)
at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.dlb.run(DL.java:) "Thread-0" prio= tid=0x022ee400 nid=0x2c50 waiting on condition [0x047ef000..0x047efb68]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x22e75a50> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:
)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:)
at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.dlb.run(DL.java:) ----
Found one Java-level deadlock:
=============================
"Thread-1":
waiting for ownable synchronizer 0x22e75958, (a java.util.concurrent.locks.ReentrantLock$NonfairSync), —— 注意这里的NonfairSync,非公平同步锁。
which is held by "Thread-0"
"Thread-0":
waiting for ownable synchronizer 0x22e75a50, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
which is held by "Thread-1"
这个时候的死锁,其实跟synchronized时候的锁是不同的,但是效果是一样的。
打印:
dlb-----------
Res.aa()
dlb-----------
Res.aa()
之后就一直‘卡住’了
tryLock的时候,打印堆栈发现:
C:\Users\Administrator>jstack
-- ::
Full thread dump Java HotSpot(TM) Client VM (11.2-b01 mixed mode, sharing): "DestroyJavaVM" prio= tid=0x01edc800 nid=0x3a54 waiting on condition [0x00000000..0x01eafd20]
java.lang.Thread.State: RUNNABLE "Thread-1" prio= tid=0x01f93800 nid=0x35a8 waiting on condition [0x0480f000..0x0480fce8]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.dlb.run(DL.java:) "Thread-0" prio= tid=0x01f90c00 nid=0x2abc waiting on condition [0x0477f000..0x0477fd68]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.Res.aa(DL.java:)
at basic.thread.dlb.run(DL.java:) "Low Memory Detector" daemon prio= tid=0x01f68000 nid=0x48d0 runnable [0x00000000..0x00000000]
java.lang.Thread.State: RUNNABLE "CompilerThread0" daemon prio= tid=0x01f63c00 nid=0x3a0c waiting on condition [0x00000000..0x045cf714]
java.lang.Thread.State: RUNNABLE "Attach Listener" daemon prio= tid=0x01f95c00 nid=0x3728 waiting on condition [0x00000000..0x00000000]
java.lang.Thread.State: RUNNABLE "Signal Dispatcher" daemon prio= tid=0x01f95000 nid=0x365c runnable [0x00000000..0x00000000]
java.lang.Thread.State: RUNNABLE "Finalizer" daemon prio= tid=0x01f1b800 nid=0x258c in Object.wait() [0x01cdf000..0x01cdfc68]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x22960b28> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:)
- locked <0x22960b28> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:) "Reference Handler" daemon prio= tid=0x01f17000 nid=0x4584 in Object.wait() [0x003cf000..0x003cfce8]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x22960a30> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:)
- locked <0x22960a30> (a java.lang.ref.Reference$Lock) "VM Thread" prio= tid=0x01f15800 nid=0x4388 runnable "VM Periodic Task Thread" prio= tid=0x01f7f000 nid=0x4154 waiting on condition JNI global references: 596 ———— 这个时候并没有发生死锁,但是,有两个线程确确实实是阻塞了。 就效果来说一样的,但是原理不同。
而且后台打印不同:
dlb-----------
Res.aa()
dlb-----------
Res.aa()
Res.aa()
Res.aa()
Res.aa()
Res.aa()
Res.aa()
Res.aa()
Res.aa()
...
一直有打印,每隔一秒钟一次———— 死循环!!!!!
。。
说明,线程有一个轮询机制,一直在等待另一个线程释放锁,但是它又不释放,如是就一直“卡”在了那里。 —— 卡,其实就相当于了‘锁’!
好吧, 其实上面的例子有问题,因为,里面出现了一个死循环。。 而且,没有判断trylock 的返回值。
使用这个例子吧,但是,惊人的发现每次的结果不一样!: 有时候很快就两个end了,有时候一个end,有时候根本没有end——每次的tryLock都能返回true ,太奇怪了吧,如上例一样一直打印
package basic.thread; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock; public class DL { public static void main(String[] args) {
Res res = new Res();
Res another = new Res();
res.setAnother(another);
another.setAnother(res);
dlb b1 = new dlb(res);
dlb b2 = new dlb(another);
b1.start();
b2.start();
}
} class dlb extends Thread{
Res res;
public dlb(Res res) {
this.res = res;
}
@Override
public void run() {
System.out.println("dlb-----------");
res.aa();
}
} class Res { Res another;
public void setAnother(Res another) {
this.another = another;
}
ReentrantLock lock = new ReentrantLock(); public void aa() {
boolean boo = lock.tryLock();
if(boo){
System.out.println("Res.aa()aaaaaaaa");
try {
Thread.sleep();
another.aa();
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
} else {
System.out.println("Res.aa() end !! ");
}
}
}
好吧,其实上面的例子都不太好。
总结:
1 一般使用lock即可。
2 使用tryLock的话,需要判断其返回值,否则就达不到锁的效果。 应该如下,注意 unlock 必须要放在if里面
boolean tryLock = lock.tryLock();
System.out.println(" trylock : " + tryLock);
if(tryLock) {
do sth.
lock.unlock(); ---- unlock 必须要放在if里面,否则如果tryLock为false的话,报错java.lang.IllegalMonitorStateException。 因为如果false,则lock 的holder 并非当前线程。。。 很明显的道理吧!
}
3 tryLock方法无阻塞,立即返回(true/false), 所以,使用tryLock是不会造成死锁的!!! 但是,正因为如此,可能到不到我们想要的目的,比如,有时候时候我就是想锁定某个资源,否则就不能继续操作。 ———— 所以说tryLock适合无阻塞的场景!
4 java-tryLock可轮询可中断可定时的锁 —— 好奇怪的名字。。
参考http://aguang520.iteye.com/blog/815575 http://zfzaizheli.iteye.com/blog/1394823 (表示看不懂。。)等
5 注意到 ReentrantLock 的 lock() 返回值为void、 而tryLock返回boolean。
6 synchronized不能和lock等混用。 synchronized的用法见我另外一篇博客
7 ReentrantLock 是接口Lock的实现,其功能、底层原理远比synchronized复杂,
8 synchronized 可以加在方法前, 代码块前。 而且可以是静态的!
9 ReentrantReadWriteLock 的用法一般是:
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
ReadLock readLock = lock.readLock(); —— 用来对get,即查询操作加锁
WriteLock writeLock = lock.writeLock();—— 用来对add/update/delete,即新增修改删除操作加锁
—— 问题是,有必要分的这么细吗? 直接一个ReentrantLock 不就行了吗?
参见 http://www.cnblogs.com/sunwei2012/archive/2010/10/09/1846358.html
http://www.cnblogs.com/GnagWang/archive/2011/02/27/1966606.html ———— 写得非常非常非常详细。。
http://www.cnblogs.com/violinn/archive/2013/05/21/multiThread1.html 非常非常非常详细而且全面的关于java锁、同步、多线程的介绍
另外注意区别FileLock 类中也有 lock 、tryLock 方法,不过,当然,用法不同。
java 锁!的更多相关文章
- 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 ...
随机推荐
- jquery选择器使用说明
在jquery中选择器是一个非常重要的东西,几乎做什么都离不开它,下面我总结了jquery几种选择器的用法.以方便后面直接可以用到!! 层次选择器: 1.find()://找到该元素的子元素以及孙子元 ...
- PhpStorm破解教程
http://www.cnblogs.com/buyucoder/p/5291771.html
- zabbix微信告警(虚拟机脚本测试成功,zabbix上收不到信息)
前言: 使用zabbix直接运行脚本又可以正常接收.但是登录zabbix web界面,测试! 动作显示已送达,但是微信并没有收到信息! 解决: 添加脚本参数,因为不添加脚本参数,调用不了你这个脚本 ...
- hdu 1142(DFS+dijkstra)
#include<iostream> #include<cstdio> #include<cmath> #include<map> #include&l ...
- 易学PHP——WAMP环境搭建
安装前的准备 查看本机的类型(x86/x64,即 32 位还是 64 位) 安装好 VC9/VC11/VC14 运行库(需要按照本机的类型选择安装) 创建好一个安装路径用于安装整套 amp 环境(我使 ...
- 可以编辑R代码的eclipse插件
说到强大的IDE,eclipse肯定是首先会被想到的几个之一,幸运地是,R也能使用它.在http://www.walware.de/goto/statet上有个StatET的插件,专门为R而做,从此R ...
- Request三种获取数据的方式
今天在做ajax请求后台代码时,发现ajax的方法都对,但就是请求不了后台代码,后来在同事帮助下才发现前台定义了两个相同参数导致请求出错. 下面记录一下request三种获取数据的方式: 1. Req ...
- SIP vs XMPP
sip和xmpp都是应用层的协议,主要用来在互联网上发送语音和即时通讯IM,rfc3521定义了sip,rfc3920定义了xmpp.xmpp来自即时通讯系统,sip类似语音和视频通信. xmpp协议 ...
- java-内省与javabean
JavaBean 是一种JAVA语言写成的可重用组件.为写成JavaBean,类必须是具体的和公共的,并且具有无参数的构造器.JavaBean 通过提供符合一致性设计模式的公共方法将内部域暴露成员属性 ...
- go json null字段的转换
最近试了试go中对json null字段进行转换,代码如下: struct 转 json: package main import ( "encoding/json" " ...