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