关于java多线程死锁的问题
最近有被问到死锁的问题,目前为止我的项目还没有遇到过死锁的问题,但是对这个问题我挺感兴趣的,所以试着写了一下解决的方案。不知道实际应用中是怎么解决的呢?有什么完整的方案,希望可以在评论区告诉我。
1)第一种,一开始想到的,应该不能算是真正意义的死锁,只是锁长时间被占用
首先加了同步锁的方法如果抛出异常,锁是会自动被释放的。所以我在下面的测试代码中,使用Thread.sleep来让这个test方法一直占用锁。
解释一下下面的类的意义, test的方法是加了同步锁的方法,是我们要执行的程序。
ctime方法是用来控制每个同步进程的总体时间不要超过5000毫秒,需要单独开启一个线程去执行。
思路很简单,在同步方法开始的时候记录下当前系统的时间, 在ctime方法中写一个while循环 每间隔一秒钟更新一下当前时间。如果当前时间减去
进程的开始大于了5秒钟。就结束当前正在执行同步方法的线程。
用tcount来统计执行完毕或者中断的线程数量,如果所有的线程都结束了就跳出while循环,这样监控线程也结束了。
用一个单独的监控线程来防止死锁。会额外的占用内存。但是目前也没有想到更好的方式。有知道相关方案的欢迎评论区留言。
public class TestThread {
static Thread nowThread;
static TestThread testThread;
static int tcount;
public synchronized void test(int a,Thread s){
nowThread=s;
time=System.currentTimeMillis();
try{
Thread.sleep(a);
System.out.println("延时了"+a);
}catch (Exception e){
System.out.println(e.getMessage());
}
tcount++;
}
static long time;
/**
* 控制时间的方法
*/
public void ctime(){
if(time==0){
time=System.currentTimeMillis();
}
long nowTime=System.currentTimeMillis();
while (tcount<3){
if(nowTime-time>5000){
try {
System.out.println("执行了结束线程操作");
synchronized (nowThread) {
nowThread.interrupt();
}
} catch ( Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
nowTime=System.currentTimeMillis();
}
time=0;
System.out.println("监控线程结束了");
}
public static void main(String [] args){
testThread=new TestThread();
new Thread(new Runnable() {
@Override
public void run() {
try {
testThread.test(10000000, Thread.currentThread());
}catch (Exception e) {
tcount++;
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
testThread.test(20000000,Thread.currentThread());
}catch (Exception e) {
tcount++;
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
testThread.test(3, Thread.currentThread());
}catch (Exception e){
tcount++;
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
testThread.ctime();
}
}).start();
}
}
程序的执行结果
执行了结束线程操作
sleep interrupted
延时了3
执行了结束线程操作
sleep interrupted
监控线程结束了
2)第二种情况,真正意义的两个线程之间的死锁,这种情况我尝试了中断线程,然而如果用sychronize的关键字的话,死锁情况是无法中断的
所以最后找到了Lock类,由于Lock加锁是可以中断的,所以还是用之前的方式,超时中断,和上面的方法差不多。只不过由于需要两个锁互相等
所以改成了用两个线程监控两个锁。一旦锁长时间没有释放,就中断线程。这时候就会抛出异常,进入catch代码块。在这里释放锁,
程序里释放锁的部分之所以两个锁都释放,是出于假设不会发生死锁的命题。实际代码中由于死锁了线程1和线程2都只会拿到一个锁,所以在unlock的时候会抛异常,
所以要用trycatch捕捉异常
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestThread {
private Thread nowThread;
static TestThread testThread,testThread2;
private int tcount;
private long time;
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public void setNowThread(Thread nowThread) {
this.nowThread = nowThread;
}
/**
* 控制时间的方法
*/
public void ctime() {
if (time == 0) {
time = System.currentTimeMillis();
}
long nowTime = System.currentTimeMillis();
while (tcount < 2) {
if (nowTime - time > 5000) {
try {
nowThread.interrupt();
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
finally {
}
System.out.println(tcount);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
nowTime = System.currentTimeMillis();
}
time = 0;
System.out.println("监控线程结束了");
}
static Lock lock1 = new ReentrantLock();
static Lock lock2 = new ReentrantLock();
public static void main(String[] args) {
testThread = new TestThread();
testThread2=new TestThread();
Thread thread;
thread= new Thread(new Runnable() {
@Override
public void run() {
try {
lock1.lockInterruptibly();
System.out.println("线程1获取锁1");
testThread.setTime(System.currentTimeMillis());
testThread.setNowThread(Thread.currentThread());
Thread.sleep(200);
lock2.lockInterruptibly();
System.out.println("线程1 获取锁2");
testThread2.setTime(System.currentTimeMillis());
testThread2.setNowThread(Thread.currentThread());
lock2.unlock();
System.out.println("线程1执行完毕");
lock1.unlock();
} catch (Exception e) {
System.out.println("执行catch");
try {
lock1.unlock();//可能会抛异常,在本线程并没有给lock加锁的情况
}catch (Exception e1){
}
try {
lock2.unlock();//可能会抛异常,在本线程并没有给lock加锁的情况
}catch (Exception e2){
}
} finally {
System.out.println("执行finally");
testThread.tcount++;
testThread2.tcount++;
}
}
});
thread.start();
thread= new Thread(new Runnable() {
@Override
public void run() {
try {
lock2.lockInterruptibly();
System.out.println("线程2 获取锁2");
testThread2.setTime(System.currentTimeMillis());
testThread2.setNowThread(Thread.currentThread());
Thread.sleep(200);
lock1.lockInterruptibly();
System.out.println("线程2 获取锁1");
testThread.setTime(System.currentTimeMillis());
testThread.setNowThread(Thread.currentThread());
lock1.unlock();
lock2.unlock();
System.out.println("线程2执行完毕");
} catch (Exception e) {
try {
lock1.unlock();//可能会抛异常,在本线程并没有给lock加锁的情况
}catch (Exception e1){
}
try {
lock2.unlock();//可能会抛异常,在本线程并没有给lock加锁的情况
}catch (Exception e2){
}
} finally {
testThread.tcount++;
testThread2.tcount++;
}
}
});
thread.start();
thread=new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
lock1.lockInterruptibly();
System.out.println("正常执行3的1获取锁1");
testThread.setTime(System.currentTimeMillis());
testThread.setNowThread(Thread.currentThread());
lock1.unlock();
System.out.println("正常执行的需要获取锁1的程序");
} catch (Exception e) {
lock1.unlock();
} finally {
testThread.tcount++;
}
}
});
thread.start();
thread= new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
lock2.lockInterruptibly();
System.out.println("正常执行4获取锁2");
testThread2.setTime(System.currentTimeMillis());
testThread2.setNowThread(Thread.currentThread());
lock2.unlock();
System.out.println("正常执行的需要获取锁2的程序");
} catch (Exception e) {
lock2.unlock();
} finally {
testThread2.tcount++;
}
}
});
thread.start();
new Thread(new Runnable() {
@Override
public void run() {
testThread.ctime();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
testThread2.ctime();
}
}).start();
}
}
执行结果
线程1获取锁1
线程2 获取锁2
0
执行catch
1
正常执行4获取锁2
执行finally
正常执行3的1获取锁1
正常执行的需要获取锁2的程序
正常执行的需要获取锁1的程序
监控线程结束了
监控线程结束了
上一篇: 爬虫练习 用beautifulsoup 爬取猫眼top100
下一篇: hive时间转换