多级锁能否在多线程程序中导致死锁?

use*_*016 0 java multithreading deadlock locks

我有一个由作家和读者组成的程序,其访问权限由监视器控制。

因此,这本来很饿,但我陷入了僵局。我想知道为什么,然后我想起我又放了一把锁,我认为这对于在读取器内部的读取方法内部是不必要的,以防止全局变量受到不一致的影响。我认为这不会造成任何死锁,因为我可以在没有任何死锁的情况下运行10000次线程,但是当我必须进行实验室演示时,它在我认为的第10010个线程处死锁。我不明白为什么会那样做。另外,我没想到它会饿死,但显然它应该这样做。

我的问题是:这些多级锁是否导致死锁?如果没有,这是什么原因造成的?

    import java.io.*;
    import java.io.IOException;
    import java.util.*;

    public class Writer extends Thread{

    private int number;

    public Writer(int number)
    {
        this.number = number;
    }

    public int getNumber()
    {
        return number;
    }

        public static void Write(String filename){

        try {

            String content = RandomString();


            File f = new File(filename);

            if (!f.exists())
            {
                f.createNewFile();
            }


            PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("Task1out.txt", true)));
            out.println(content);
            out.close();


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static String RandomString(){

        String chars = new String("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
        int n = chars.length();

        String randomString = new String();
        Random r = new Random();

            for (int i=0; i<100; i++)
            {
                randomString = randomString + chars.charAt(r.nextInt(n));
            }

        System.out.println("RandomString() generated: " + randomString);

        return randomString;

    }



    public void run(){

        try{

        //FileControl fc = new FileControl();

            int number = this.getNumber();


            for(int i = 0; i <1000; i++) //CHANGE IT TO 1000
            {
                main.fc.WriterEntry(number);

                //write file random characters (must append)

                Write("Task1out.txt");

                main.fc.WriterExit(number);

            }
        } catch(InterruptedException e)
        {
            System.out.println("Interrupted Exception caught");
        }

    }


}
Run Code Online (Sandbox Code Playgroud)

这是作家班。

    import java.io.BufferedWriter;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileWriter;
    import java.io.FileReader;
    import java.io.IOException;
    import java.util.*;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;



public class Reader extends Thread{


    private int number;

    public Reader(int number)
    {
        this.number = number;
    }


    public int getNumber()
    {
        return number;
    }

        public static synchronized void Read(String filename)throws InterruptedException{

        BufferedReader br = null;





            main.lock.lock(); //lock
        try{




        try {


            String line;
            char[] chars = new char[100];
            int readIndex2 = 0;
            int addToIndex = 0;



            br = new BufferedReader(new FileReader(filename));


            int initialReadIndex = main.getIndex();




            System.out.println("initial read index: " + initialReadIndex);

            while ((line = br.readLine()) != null && readIndex2 < initialReadIndex+100 && addToIndex < 100) {

                for(int i = 0; i< 100; i++)
                {
                    if (initialReadIndex == readIndex2 || initialReadIndex < readIndex2)
                    {

                        if(line.length() > addToIndex)
                        {




                        chars[i] = line.charAt(i);
                        addToIndex++;
                        }


                    }
                    else
                    {
                        readIndex2++;
                    }
                }
                System.out.println(chars);
            }

            if(line == null)
            {
                System.out.println("nothing to read");
            }



            main.incrementIndex(addToIndex);


            System.out.println("current read index: " + (initialReadIndex + addToIndex));





        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("buffered reader exception");
        } finally {


            try {


                if (br != null)
                    {

                    br.close();
                    }
            } catch (IOException ex) {
                ex.printStackTrace();
                System.out.println("exception during closing");
            }
        }
        }finally{
            main.lock.unlock(); //lock

        }

        }


    public void run(){

        try{


        //FileControl fc = new FileControl();


        int number = this.getNumber();


            for(int i = 0; i <1000; i++) //CHANGE IT TO 1000
            {
                main.fc.ReaderEntry(number);

                //read file

                Read("Task1out.txt");

                main.fc.ReaderExit(number);
            }
        } catch(InterruptedException e)
        {
            System.out.println("Interrupted Exception caught");
        }

    }



        }
Run Code Online (Sandbox Code Playgroud)

这是读者类。

 import java.io.BufferedWriter;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileWriter;
    import java.io.FileReader;
    import java.io.IOException;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;

    public class main{

    public static FileControl fc = new FileControl();

    final static Lock lock = new ReentrantLock();

    public static int readIndex;

    public static void incrementIndex(int increment) {


                readIndex = readIndex + increment;

    }

    public static int getIndex()
    {
        return readIndex;
    }



    public static void main(String[] args) throws InterruptedException {



            Writer [] writer = new Writer[10];
            Reader [] reader = new Reader[10];

            for(int i = 0; i < 10; i++)
            {
                reader[i] = new Reader(i);
                writer[i] = new Writer(i);
                //creating readers and writers

            }

            for(int i = 0; i < 10; i++)
            {
                //anonymous threads
                //(new Thread(new Writer())).start();
                //(new Thread(new Reader())).start();

                reader[i].start();
                writer[i].start();

            }




            for(int i = 0; i < 10; i++)
            {
                try{
                    reader[i].join();
                    writer[i].join();
                } catch(InterruptedException e){
                    e.printStackTrace();
                }


            }






        }

}
Run Code Online (Sandbox Code Playgroud)

这是主要的类。

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;


    public class FileControl {
    final Lock lock = new ReentrantLock();
    final Condition writers = lock.newCondition();
    final Condition readers = lock.newCondition();
    int activereaders = 0;
    int waitingwriters = 0;
    boolean writing = false;

    public void WriterEntry(int number)throws InterruptedException{
        lock.lock();
        try{
                if(writing == true || activereaders > 0){
                    waitingwriters++;
                    System.out.println("Writer thread " + number + " : waiting to write");
                    writers.await();
                    waitingwriters--;
                }
                System.out.println("Writer thread " + number + " : ready to write");

                writing = true;
           }
        finally{
            lock.unlock();
        }


    }



    public void WriterExit(int number)throws InterruptedException{
        lock.lock();
        try{
            System.out.println("Writer thread " + number + " : finished to write");

            System.out.println("writers " + waitingwriters + "readers " + activereaders); //test

            if(waitingwriters > 0)
                writers.signal();
            else{
                writing = false;
                readers.signal();
            }
        }
        finally{
            lock.unlock();
        }

    }


    public void ReaderEntry(int number)throws InterruptedException{
        lock.lock();
        try{

            if(writing == true || waitingwriters > 0){ //remove activereaders > 0
                System.out.println("Reader thread " + number + " : waiting to read");
                readers.await();
                activereaders++;
            }


            System.out.println("Reader thread " + number + " : ready to read");
        }
        finally{
            lock.unlock();
        }

    }

    public void ReaderExit(int number)throws InterruptedException{
        lock.lock();
        try{



        activereaders--;



        System.out.println("Reader thread " + number + " : finished to read");

        System.out.println("writers " + waitingwriters + "readers " + activereaders); //test

            if(activereaders == 0)
            {
                if(waitingwriters > 0)
                {
                    writers.signal();
                }
                else
                {
                    readers.signal();
                }
            }
        }
        finally{
            lock.unlock();
        }

    }


}
Run Code Online (Sandbox Code Playgroud)

这是监视器。

监视器的伪代码

voi*_*gic 5

每当您拥有多个锁A,B和C时,如果您不能保证代码尝试以相同的顺序获取所述锁,则可能会产生死锁。

final Lock A = new ReentrantLock();
final Lock B = new ReentrantLock();
final Lock C = new ReentrantLock();
Run Code Online (Sandbox Code Playgroud)

A,B,C或C,B,A或A,C,B-顺序无关紧要。

当您尝试一个代码路径尝试以下问题时:A,B,C而另一个尝试C,B,A。

您可能会猜到,由于A和C都被保留,所以两者之一将变为B,然后两者都将死锁。(又在资源锁定图中有一个循环)

正式地说,只有满足以下所有条件,才会出现死锁:

  1. 无抢占:分配后系统不会释放资源;它们只能在保存过程中释放。
  2. 循环等待:上面讨论了。
  3. 互斥:在任何给定时间,只有一个进程可以使用资源。
  4. 资源持有:一个进程当前正在至少持有一个资源,并正在请求/等待另一进程持有的其他资源。

最好的解决方案是确保订单一致或锁定在较高(单个)级别。另一个选择是使用一个锁定库,该库在尝试锁定时会超时(或使用条件并编写自己的包装器来执行此操作)。但是这种方法并不适合胆小的人。此方法的某些实现将等待随机的时间,然后重试,但是随着锁数量的增加,此方法效率极低。

资源:

PS我实际上并没有阅读太多代码,因为它的格式不正确,并且不是一个最小的示例(即,对于我们这里的目的来说太冗长了)。但是,此建议应从理论角度回答您的问题。