Frage

Ich habe ein Programm mit Schriftstellern und Lesern und deren Zugangsrecht wird von einem Monitor kontrolliert.

Das sollte also verhungern, aber ich bekam einen Deadlock. Ich habe mich gefragt, warum und dann erinnerte ich mich, dass ich ein weiteres Schloss einstellte, was meiner Meinung nach in meiner Lesemethode in den Lesern unnötig war, um meine globale Variable vor Inkonsistenzen zu schützen. Ich dachte, es würde keine Deadlock verursachen, weil ich die Threads 10000 Mal ohne Deadlock auftreten könnte, aber wenn ich meine Labor -Demo machen musste, war es beim 10010. Thread, denke ich, abgestimmt. Ich verstehe nicht, warum es das tun würde. Außerdem hatte ich nicht erwartet, dass es verhungern würde, aber anscheinend sollte es es tun.

Meine Frage ist: Sind diese mehrstufigen Schlösser für die Deadlock verantwortlich? Wenn nicht, was verursacht das?!

    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");
        }

    }


}

Dies ist die Schriftstellerklasse.

    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");
        }

    }



        }

Dies ist die Leserklasse.

 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();
                }


            }






        }

}

Dies ist die Hauptklasse.

    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();
        }

    }


}

Dies ist der Monitor.

Pseudocode für den Monitor

War es hilfreich?

Lösung

Wann immer Sie mehrere Schlösser A, B und C haben, können Sie Deadlock haben, wenn Sie nicht garantieren, dass Ihr Code versucht, diese Schlösser in derselben Reihenfolge zu erwerben.

final Lock A = new ReentrantLock();
final Lock B = new ReentrantLock();
final Lock C = new ReentrantLock();

A, b, c oder c, b, a oder a, c, b - es spielt keine Rolle, solange die Reihenfolge konsistent ist.

Ein Problem tritt auf, wenn Sie einen Codepfad haben, den Sie versuchen für: a, b, c und einen anderen, der nach C, B, a.

Wie Sie wahrscheinlich erraten können, da A und C beide gehalten werden, wird einer der beiden B und dann BEDLOCK. (AKA Sie haben einen Zyklus im Ressourcenverriegelungsdiagramm)

Formell sprechend kann Deadlock entstehen nur wenn Alle folgenden Bedingungen finden:

  1. Keine Präsentation: Das System gibt nach Zuteilung keine Ressourcen. Sie können nur durch den Haltevorgang freigegeben werden.
  2. Rundschreiben: oben besprochen.
  3. Gegenseitiger Ausschluss: Nur ein Prozess kann zu einem bestimmten Zeitpunkt eine Ressource verwenden.
  4. Ressourcenbestand: Derzeit hält ein Prozess mindestens eine Ressource und fordert/wartet auf zusätzliche Ressourcen, die von einem anderen Prozess gehalten werden.

Die beste Lösung besteht darin, sicherzustellen, dass die Reihenfolge konsistent ist oder auf einer höheren (einzelnen) Ebene sperrt. Eine andere Option ist die Verwendung einer Sperrenbibliothek, die beim Versuch, zu sperren (oder Bedingungen zu verwenden und einen eigenen Wrapper zu schreiben, der dies tut). Dieser Ansatz ist jedoch nicht für schwache Nerven. Eine gewisse Implementierung davon wird eine zufällige Zeit warten und es erneut versuchen, aber dies kann mit zunehmender Anzahl der Schlösser sehr ineffizient sein.

Ressourcen:

PS Ich habe nicht viel von Ihrem Code gelesen, da es schlecht formatiert ist und kein minimales Beispiel ist (dh zu windig für unsere Zwecke hier). Dieser Rat sollte jedoch Sie aus theoretischer Sicht beantworten.

Andere Tipps

Es ist sicherlich möglich. Es ist auch möglich, dass Sie zur Laufzeit überprüfen!

Der erste Schritt besteht darin, den Thread -Dump zu erhalten. Hier sind drei Methoden:

  • Wenn Sie den Prozess in VisualVM öffnen und auf die Registerkarte "Threads" gehen, wird Ihnen angegeben, ob er diese Art von Deadlock erkennt. Sie können dann einen Thread -Dump durchführen (genau dort gibt es eine Taste), die Ihnen zeigt, was jeder Thread tut, sowie alle Schlösser, die sie besitzt, und alle Sperren (falls vorhanden), die er erwerben versucht.
  • Unter Linux oder Mac können Sie den Stapel durch Ausgabe erhalten kill -3 <pid>, wo <pid> Ist Ihr Java -Prozess 'ID. Es wird denselben Thread -Dump zu Stderr fallen lassen. Der Boden dieses Thread -Dumps enthält auch eine Zusammenfassung der nachgewiesenen Deadlocks. Ich weiß nicht, wie man das unter Windows macht.
  • Sie können auch aufrufen jstack <pid>, die den Thread -Dump zu stdout (die drucken jstack"S stdout, nicht der ursprüngliche Java -Prozess").

Ich habe ein Beispielprogramm geschrieben, das Deadlocks und leitete es (siehe Mein Kern). Der relevante Abschnitt des Thread -Dumps lautet:

Found one Java-level deadlock:
=============================
"Thread-2":
  waiting for ownable synchronizer 7f42b0f38, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
  which is held by "Thread-1"
"Thread-1":
  waiting for ownable synchronizer 7f42ba170, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
  which is held by "Thread-2"

Und die relevanten Thread -Zustände sind:

"Thread-2" prio=5 tid=7fc01c911000 nid=0x113d18000 waiting on condition [113d17000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <7f30c3528> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:842)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1178)
    at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:186)
    at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:262)
    at Locky$Boomer.run(Locky.java:22)
    at java.lang.Thread.run(Thread.java:680)

   Locked ownable synchronizers:
    - <7f30c3558> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

"Thread-1" prio=5 tid=7fc01d06c800 nid=0x113c15000 waiting on condition [113c14000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <7f30c3558> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:811)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:842)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1178)
    at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:186)
    at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:262)
    at Locky$Boomer.run(Locky.java:22)
    at java.lang.Thread.run(Thread.java:680)

   Locked ownable synchronizers:
    - <7f30c3528> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

Dies wird nicht funktionieren alle Deadlocks. Zum Beispiel werden Deadlocks aufgrund des Wartens auf externe Ressourcen nicht erwischt. Aber es wird fangen Lock-basierte Deadlocks sowie synchronized-basierte.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top