自己设计一个死锁,来理解死锁的原理。
死锁的定义是,两个或两个以上的线程或进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象。
简化一下,就当成只有两个线程。现在有线程1和线程2。线程1执行过程中,先锁定了对象a,然后需要再锁定b才能继续执行代码;而线程2正巧相反,先锁定了b,需要再锁定a才能继续执行代码。这时,两个线程都等着对方解锁,才能继续执行,这时,两个线程就进入等待状态,最终不会有线程执行。这就变成了死锁。
代码如下:
package deadLockDemo;
public class ThreadTest {
public static void main(String[] args){
Thread t9=new Thread(new DeadLock(true));
Thread t10=new Thread(new DeadLock(false));
t9.start();
t10.start();
}
}
class DeadLock implements Runnable{
boolean lockFormer;
static Object o1=new Object();
static Object o2=new Object();
DeadLock(boolean lockFormer){
this.lockFormer=lockFormer;
}
@Override
public void run(){
if(this.lockFormer){
synchronized (o1){
try{
Thread.sleep(500);
}catch(InterruptedException e){
e.printStackTrace();
}
synchronized (o2){
System.out.println("1ok");
}
}
}else{
synchronized (o2){
try{
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}
synchronized (o1){
System.out.println("2ok");
}
}
}
}
}
从以上例子中可以看出,陷入死锁是因为加了多个锁,如果尽量减少加锁,可以避免死锁。
参考https://blog.csdn.net/qq_35064774/article/details/51793656
死锁发生的原因:
1、系统资源有限
2、进程或线程推进顺序不恰当
3、资源分配不当
死锁发生的四个条件:
1、互斥条件:一份资源每次只能被一个进程或线程使用(在Java中一般体现为,一个对象锁只能被一个线程持有)
2、请求与保持条件:一个进程或线程在等待请求资源被释放时,不释放已占有资源
3、不可剥夺条件:一个进程或线程已经获得的资源不能被其他进程或线程强行剥夺
4、循环等待条件:形成一种循环等待的场景
package deadLockDemo;
public class TestDeadLock implements Runnable {
A a = new A();
B b = new B();
public void init() throws InterruptedException{
Thread.currentThread().setName("主线程");
a.waitMethod(b);
}
@Override
public void run() {
Thread.currentThread().setName("副线程");
try {
b.waitMethod(a);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws InterruptedException{
TestDeadLock testDeadLock = new TestDeadLock();
Thread thread = new Thread(testDeadLock);
thread.start();
testDeadLock.init();
}
}
class A {
public synchronized void waitMethod(B b) throws InterruptedException{
System.out.println(Thread.currentThread().getName() + ":正在执行a的等待方法,持有a的对象锁");
Thread.sleep(2000L);
System.out.println(Thread.currentThread().getName() + ":试图调用b的死锁方法,尝试获取b的对象锁");
b.deadLockMethod();
}
public synchronized void deadLockMethod(){
System.out.println(Thread.currentThread().getName() + ":正在执行a的死锁方法,持有a的对象锁");
}
}
class B {
public synchronized void waitMethod(A a) throws InterruptedException{
System.out.println(Thread.currentThread().getName() + ":正在执行b的等待方法,持有b的对象锁");
Thread.sleep(2000L);
System.out.println(Thread.currentThread().getName() + ":试图调用a的死锁方法,尝试获取a的对象锁");
a.deadLockMethod();
}
public synchronized void deadLockMethod(){
System.out.println(Thread.currentThread().getName() + ":正在执行B的死锁方法,持有B的对象锁");
}
}
通过sleep()方法,可以实现主线程持有a的对象锁并请求b的对象锁、副线程持有b的对象锁并请求a的对象锁的场景,即发生死锁。
结果如下:
D:\Java\jdk\bin\java -javaagent:D:\IdeaIU\lib\idea_rt.jar=55036:D:\IdeaIU\bin -Dfile.encoding=UTF-8 -classpath D:\Java\jdk\jre\lib\charsets.jar;D:\Java\jdk\jre\lib\deploy.jar;D:\Java\jdk\jre\lib\ext\access-bridge-64.jar;D:\Java\jdk\jre\lib\ext\cldrdata.jar;D:\Java\jdk\jre\lib\ext\dnsns.jar;D:\Java\jdk\jre\lib\ext\jaccess.jar;D:\Java\jdk\jre\lib\ext\jfxrt.jar;D:\Java\jdk\jre\lib\ext\localedata.jar;D:\Java\jdk\jre\lib\ext\nashorn.jar;D:\Java\jdk\jre\lib\ext\sunec.jar;D:\Java\jdk\jre\lib\ext\sunjce_provider.jar;D:\Java\jdk\jre\lib\ext\sunmscapi.jar;D:\Java\jdk\jre\lib\ext\sunpkcs11.jar;D:\Java\jdk\jre\lib\ext\zipfs.jar;D:\Java\jdk\jre\lib\javaws.jar;D:\Java\jdk\jre\lib\jce.jar;D:\Java\jdk\jre\lib\jfr.jar;D:\Java\jdk\jre\lib\jfxswt.jar;D:\Java\jdk\jre\lib\jsse.jar;D:\Java\jdk\jre\lib\management-agent.jar;D:\Java\jdk\jre\lib\plugin.jar;D:\Java\jdk\jre\lib\resources.jar;D:\Java\jdk\jre\lib\rt.jar;G:\IntelliJ_workspace\SpringTest\out\production\SpringTest;G:\IntelliJ_workspace\SpringTest\lib\spring-instrument-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-instrument-tomcat-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-aspects-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-context-support-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-jms-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-expression-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-beans-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-jdbc-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-oxm-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-context-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-aop-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\aopalliance-1.0.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-messaging-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\commons-logging-1.2.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-test-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-tx-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-orm-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-core-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-webmvc-portlet-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-web-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-webmvc-4.3.14.RELEASE.jar;G:\IntelliJ_workspace\SpringTest\lib\spring-websocket-4.3.14.RELEASE.jar;D:\IdeaIU\lib\junit-4.12.jar;D:\IdeaIU\lib\hamcrest-core-1.3.jar deadLockDemo.TestDeadLock
主线程:正在执行a的等待方法,持有a的对象锁
副线程:正在执行b的等待方法,持有b的对象锁
主线程:试图调用b的死锁方法,尝试获取b的对象锁
副线程:试图调用a的死锁方法,尝试获取a的对象锁