欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于java多线程死锁的问题

程序员文章站 2022-05-02 17:06:19
...

最近有被问到死锁的问题,目前为止我的项目还没有遇到过死锁的问题,但是对这个问题我挺感兴趣的,所以试着写了一下解决的方案。不知道实际应用中是怎么解决的呢?有什么完整的方案,希望可以在评论区告诉我。

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的程序
监控线程结束了
监控线程结束了