Read/Write Lock

0

Cześć, męczę się z takim zadaniem.

//"Napisać program Author-Writer z wykładu przy użyciu blokujących kolejek.
Jako argumenty program otrzymuje napisy, które co sekundę ma generować Author.
Writer ma je wypisywać na konsoli.

Klasa Main ma następująca postać i nie można jej modyfikować."//

package zad4;

public class Main {
  public static void main(String[] args) {
    Author autor = new Author(args);
    new Thread(autor).start();
    new Thread(new Writer(autor)).start();
  }
}
package zad4;

public class Writer implements Runnable {

    Author TEXT_AUTHOR;

    public Writer(Author ath){
        TEXT_AUTHOR = ath;
    }

    @Override
    public void run() {
        String TEXT = TEXT_AUTHOR.getTextToWrite();
        while(TEXT != null) {
          System.out.println("-> " + TEXT);
          TEXT = TEXT_AUTHOR.getTextToWrite();
          }
      } 
}
package zad4;

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

public class Author implements Runnable {

    public static String TEXT = null;
    public static boolean NEW_CONTROLER = false;
    Lock lock = new ReentrantLock();
    String[] ARGUMENTS;

    public Author(String[] args){
        ARGUMENTS = args;
    }

    //Method setting text 
    public void setTextToWrite(String s) {
        while (NEW_CONTROLER == true) {
            try {
                wait();
            } catch(InterruptedException exc) {}
        }
        TEXT = s;
        NEW_CONTROLER = true;
        notifyAll();
    }

    //Method getting text
    String getTextToWrite() {
        while (NEW_CONTROLER == false) {
            try {
                wait();
            } catch (InterruptedException e) {}
        }
        NEW_CONTROLER = false;
        notifyAll();
        return TEXT;
      }

    public void run() {

        for(int i=0; i<ARGUMENTS.length; i++){
            try {
                lock.lock();
                Thread.sleep(1000);
                lock.unlock();
            } catch (InterruptedException e) {}
            setTextToWrite(ARGUMENTS[i]);
            NEW_CONTROLER = false;
        }
    }
}  

Poki co rzuca mi takie cuda

Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
    at java.lang.Object.wait(Native Method)
    at java.lang.Object.wait(Unknown Source)
    at zad4.Author.getTextToWrite(Author.java:42)
    at zad4.Writer.run(Writer.java:19)
    at java.lang.Thread.run(Unknown Source)
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
    at java.lang.Object.notifyAll(Native Method)
    at zad4.Author.setTextToWrite(Author.java:35)
    at zad4.Author.run(Author.java:62)
    at java.lang.Thread.run(Unknown Source)

Rozwiązania nie oczekuję, ale jakiejś podpowiedzi, bo siedzę nad tym już drugi dzień :/.

Pozdrawiam

0

Żeby użyć coś.wait() musisz najpierw być w synchronized (coś) { ... }. W szczególnym (i najbardziej popularnym) przypadku coś może być tożsame z this.

ZTCP to by coś.wait() się zakończyło to inny wątek który też jest w synchronized (coś) { ... } musiałby wywołać coś.notify() bądź coś.notifyAll(). Różnica między nimi jest taka, że notify() wybudza jeden czekający wątek, a notifyAll() wszystkie.

0

Miałem skupić się na lockach, więc zdecydowałem się przerobić całość.

public class Main {
  public static void main(String[] args) {
    Author autor = new Author(args);
    new Thread(autor).start();
    new Thread(new Writer(autor)).start();
  }
}
public class Writer implements Runnable {

    Author TEXT_AUTHOR;

    public Writer(Author ath){
        TEXT_AUTHOR = ath;
    }

    @Override
    public void run() {
        String TEXT = TEXT_AUTHOR.getTextToWrite();
        System.out.println(TEXT);
        while(TEXT != "DONE") {
          System.out.println(TEXT);
          TEXT = TEXT_AUTHOR.getTextToWrite();
          }
      }
}
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Author implements Runnable {

    static String TEXT = null;
    static boolean NEW_CONTROLER = false;
    Lock lock = new ReentrantLock();
    String[] ARGUMENTS;

    public Author(String[] args){
        ARGUMENTS = args;
    }

    //Method setting text 
    public void setTextToWrite(String s) {
        if (NEW_CONTROLER == false){
            lock.lock();
            TEXT = s;
            //System.out.println("Text has been set " + TEXT);
            NEW_CONTROLER = true;
            lock.unlock();
        }
    }

    //Method getting text
    String getTextToWrite() {
        if (NEW_CONTROLER == true){
            lock.lock();
            NEW_CONTROLER = false;
            lock.unlock();
            //return TEXT;
        }

        return TEXT;
        //return null;
      }

    public void run() {

        for(int i=0; i<ARGUMENTS.length; i++){
            try {
                lock.lock();
                Thread.sleep(1000);
                lock.unlock();
            } catch (InterruptedException e) {}
            lock.lock();
            setTextToWrite(ARGUMENTS[i]);
            NEW_CONTROLER = false;
            lock.unlock();
        }

        TEXT="DONE";

    }
}  

Całość uproszczona z tym że locki zdaje się że źle założone. Niby zmienia kolejne argumenty z tym że pętla wypisująca we writerze w między czasie zakręci się kilkadziesiąt razy i output jest paskudny.

jeden
jeden
jeden
jeden
....
dwa
dwa
dwa
dwa
dwa
...
trzy
trzy
trzy
trzy
........
cztery
1

Zastanawia mnie tylko po co w ogóle kombinujesz z lockami? W zadaniu masz wprost napisane że masz użyć blokujących kolejek. Jeśli możesz użyć wbudowanych to jest dostępna jest java.util.concurrent.SynchronousQueue<e>, która ma metody void put(E e) i E take(), które załatwiają sprawę. Ewentualnie są też inne klasy typu BlockingQueue<e>.

0

Całość przepisana na BlockingQueue. Kurde... Tyle czasu stracone, a wystarczyło lepiej wybrać kierunek od początku. Mógłbym tylko prosić o przejrzenia czy można to zrobić w lepszy sposób? Albo czy nie przeoczyłem niczego.

public class Main {
  public static void main(String[] args) {
    Author autor = new Author(args);
    new Thread(autor).start();
    new Thread(new Writer(autor)).start();
  }
}
public class Writer implements Runnable {
    Author TEXT_AUTHOR;

    public Writer(Author ath){
        TEXT_AUTHOR = ath;
    }

    @Override
    public void run() {
        while(TEXT_AUTHOR.getTEXT_CONTROLER() != false){
            try {
                System.out.println(TEXT_AUTHOR.QUEUE.take());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }    
    }
}
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

public class Author implements Runnable {

    public BlockingQueue<String> QUEUE = new ArrayBlockingQueue<String>(1024);
    private static boolean WRITER_CONTROLER = true;
    String[] ARGUMENTS;

    public Author(String[] args){
        ARGUMENTS = args;
    }

    public void run() {
        for(int i=0; i<ARGUMENTS.length; i++){
            try {
                Thread.sleep(1000);
                QUEUE.put(ARGUMENTS[i]);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }   

        }
        setTEXT_CONTROLER(false);

    }

    public static boolean getTEXT_CONTROLER() {
        return WRITER_CONTROLER;
    }

    public static void setTEXT_CONTROLER(boolean control) {
        WRITER_CONTROLER = control;
    }
}  
0

Jeśli działa to spoko. Ćwiczeniowiec i tak poda ci swoje przemyślenia.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0