下面是一个由于同步导致线程死锁的例子:
package com.cn.gao;
public class ThreadLock implements Runnable{
private static Object obj1 = new Object(); //此处必须定义为static变量,这样才能使两个线程共享一个资源变量
private static Object obj2 = new Object();
Boolean flag = true;
@Override
public void run() {
if(flag){
synchronized(obj1){
System.out.println(Thread.currentThread().getName() + ":我已经锁定obj1,休息2s就去锁定obj2");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(obj2){
System.out.println(Thread.currentThread().getName() + ":我已锁定全部资源");
}
}
}else{
synchronized(obj2){
System.out.println(Thread.currentThread().getName() + ":我已经锁定obj2,休息2s就去锁定obj1");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(obj1){
System.out.println(Thread.currentThread().getName() + ":我已锁定全部资源");
}
}
}
}
public static void main(String args[]){
ThreadLock t1 = new ThreadLock();
ThreadLock t2 = new ThreadLock();
t1.flag = true;
t2.flag = false;
Thread thread1 = new Thread(t1,"线程1");
Thread thread2 = new Thread(t2,"线程2");
thread1.setPriority(Thread.MAX_PRIORITY);
thread2.setPriority(Thread.MIN_PRIORITY);
thread1.start();
thread2.start();
}
}
输出:
<pre name="code" class="plain" style="color: rgb(56, 56, 56); font-size: 14px; line-height: 21.9999923706055px;">线程1:我已经锁定obj1,休息2s就去锁定obj2
线程2:我已经锁定obj2,休息2s就去锁定obj1
那么为什么会产生死锁呢?
1.因为系统资源不足。
2.进程运行推进的顺序不合适。
3.资源分配不当。
学过操作系统的朋友都知道:产生死锁的条件有四个:
1.互斥条件:所谓互斥就是进程在某一时间内独占资源。(就是说多个线程在某个时间内不能同时使用某一资源)
2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。(占有等待)(就是说一个线程需要拥有多个资源才能完成任务,他将一直占有已拥有的资源直到他拥有全部所需要的资源)
3.不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。(所有的线程优先级相同,不能在别的线程没有释放资源的情况下强行夺走其资源)
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。(没有资源满足的线程无限期的等待)
1.因为系统资源不足。
2.进程运行推进的顺序不合适。
3.资源分配不当。
学过操作系统的朋友都知道:产生死锁的条件有四个:
1.互斥条件:所谓互斥就是进程在某一时间内独占资源。(就是说多个线程在某个时间内不能同时使用某一资源)
2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。(占有等待)(就是说一个线程需要拥有多个资源才能完成任务,他将一直占有已拥有的资源直到他拥有全部所需要的资源)
3.不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。(所有的线程优先级相同,不能在别的线程没有释放资源的情况下强行夺走其资源)
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。(没有资源满足的线程无限期的等待)
如何解决死锁,大家可以从死锁的四个条件去解决,只要破坏了一个必要条件,那么我们的死锁就解决了。在java中使用多线程的时候一定要考虑是否有死锁的问题哦。
- 打破互斥条件
如果想要打破这个条件,就是要让多个线程共享资源,比如说一个读线程,还有一个写线程,如果他们可以同时操作同一个文件,则有可能读到脏数据。所以一般不从这方面考虑打破死锁
- 打破占有等待
当检测到自己所需要的资源被别的线程占用,则立即释放自己占用的资源,或者等待某一固定时间,若还没有得到该资源,则立即释放自己所拥有的资源
- 打破不剥夺条件
给所以的线程设定优先级,如有三个线程(优先级从高到低)A/B/C,当A需要某个资源时,如果此时C正在占用他,因为A的优先级高于C,所以C必须立马释放该资源
- 打破循环等待条件
如果等待一段时间,还没有得到自己所需要的资源,则立马释放自己拥有的所有资源
下面是通过wait()方法释放对同步监视器的锁定,然后再通过notifyAll()释放对同步监视器的锁定
package com.cn.gao;
public class ThreadLock implements Runnable{
private static Object obj1 = new Object(); //此处必须定义为static变量,这样才能使两个线程共享一个资源变量
private static Object obj2 = new Object();
Boolean flag = true;
@Override
public void run() {
if(flag){
synchronized(obj1){
System.out.println(Thread.currentThread().getName() + ":我已经锁定obj1,休息2s就去锁定obj2");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//先调用obj1的wait()方法,导致当前线程等待,且当前线程会释放对同步监视器的锁定
try {
obj1.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(obj2){
System.out.println(Thread.currentThread().getName() + ":我已锁定全部资源");
}
}
}else{
synchronized(obj2){
System.out.println(Thread.currentThread().getName() + ":我已经锁定obj2,休息2s就去锁定obj1");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized(obj1){
System.out.println(Thread.currentThread().getName() + ":我已锁定全部资源");
obj1.notifyAll(); //唤醒在此同步监视器上等待的所有线程
}
}
}
}
public static void main(String args[]){
ThreadLock t1 = new ThreadLock();
ThreadLock t2 = new ThreadLock();
t1.flag = true;
t2.flag = false;
Thread thread1 = new Thread(t1,"线程1");
Thread thread2 = new Thread(t2,"线程2");
thread1.start();
thread2.start();
}
}
输出:
线程1:我已经锁定obj1,休息2s就去锁定obj2
线程2:我已经锁定obj2,休息2s就去锁定obj1
线程2:我已锁定全部资源
线程1:我已锁定全部资源
虽然目前已经知道解决死锁的方法,但是具体应该怎么操作还不是很清楚。
比如说打破不剥夺条件里面:如有三个线程(优先级从高到低)A/B/C,当A需要某个资源时,如果此时C正在占用他,因为A的优先级高于C,所以C必须立马释放该资源
我是如何知道线程c正在占用该资源,如有人知道麻烦告知一下