Java - Synchronizacja i Koordynacja wątków - drugi wątek nie wstaje

0

Witajcie,
mam problem z zadaniem dotyczącym synchronizacji i koordynacji wątków. Analizowałem kod i internet wiele razy, mimo to nie udało mi się dojść do rozwiązania.

Po wystartowaniu wątku 1 (wczytywanie z pliku), po spełnieniu warunku przekazania sterowania do drugiego wątku - pierwszy zatrzymuje się ale drugi nie rozpoczyna pracy.

 public class Main {

  public static void main(String[] args)throws InterruptedException  {
  
	  (new Thread(new Wczytywanie())).start();
	 (new Thread(new Weight())). start();
		}
}
 

import java.util.ArrayList;
public class Towary {
int id_towaru;
double waga;
int idtest =1111;
double wagatest = 23131;
static int countobj = 0;
static int notifnewobj = 200;
public static ArrayList<Towary> listatowarow = new ArrayList<Towary>();

public Towary(int id_towaru, double waga){
	this.id_towaru = id_towaru;
	this.waga=waga;
	countobj ++ ;
}
void add(int a, double b){
	listatowarow.add(new Towary(a, b));
}
public static int countob(){
	return countobj;
}

double returnweight(){
	return waga;
}

}

import java.io.File;
import java.util.Scanner;
import java.io.FileNotFoundException;
public class Wczytywanie implements Runnable {
	public static boolean state = false;
static int count = 0;
	
	public void run() {

	

		  Scanner s;
		try {

			s = new Scanner(new File("C:/Users/Janusz/Desktop/Towary.txt"));
			synchronized (this){
				
			while (s.hasNext()){
				if (count - Weight.counter > 1000){
					System.out.println(count - Weight.counter);
					state = true;
			this.notifyAll();
				}
				while (state){
					try {
				        this.wait();
				      } catch(InterruptedException exc) {}
				}
					
				count ++;
				String[] data = s.nextLine().split("\\s+"); 
				
			Towary.listatowarow.add(new Towary(Integer.parseInt(data[0]), Double.parseDouble(data[1])));
			if(Towary.countob() % Towary.notifnewobj == 0){
				System.out.println("utworzono " + Towary.countob() + " obiektów");
				System.out.println("STATE " + state);
			}
				
			

				
				}
				}
			
			s.close();
			state = true;
			//notifyAll();
			System.out.println("-------------/n TOTAL : utworzono " + Towary.countob() + " obiektów");
		} catch (FileNotFoundException e) {
			}
		}

}
public class Weight implements Runnable{

static double actualweight;
static int counter = 0;

public void run(){
	
		
	synchronized (this){
while(!(Wczytywanie.state))
{

	try {
        wait();
      } catch(InterruptedException exc) {}
}

	for (Towary t : Towary.listatowarow){
		actualweight= actualweight + t.returnweight();
		counter++;
		if(counter % 100 == 0){
			System.out.println("zważono " + counter + " obiektów");
	}
		if (Wczytywanie.count - counter < 10 ) Wczytywanie.state = false;
		notifyAll();
	}
System.out.println ("policzono wage " + Towary.countob() +" towarów");
System.out.println("-------------/n TOTAL : waga " + actualweight);
}
}

}

Bardzo prosze o wskazówki

0

mysle ze jest tu wiecej niz jeden problem, ale odpowiadajac na pytanie - wait() w watku Weight bedzie czekalo w nieskonczonosc bo nigdzie nie robisz dla niego notifyAll (musisz uzyc tego samego obiektu do notifyAll na ktorym zrobiles wait())

1
katelx napisał(a):

(musisz uzyc tego samego obiektu do notifyAll na ktorym zrobiles wait())

Wydaje mi się czy jedynym wymaganiem dla notify jest pobranie tego samego Lock'a na których synchronizował[czy też właśnie pobrał ów Locka] wait ?

A autor pytania powinien użyć CountDownLatch'a

0
niezdecydowany napisał(a):

Wydaje mi się czy jedynym wymaganiem dla notify jest pobranie tego samego Lock'a na których synchronizował[czy też właśnie pobrał ów Locka] wait ?

wlasnie to napisalam, w javie (co zreszta c# malo sprytnie zmalpowal) kazdy obiekt moze byc lockiem.
gdy robi wait() w Weight to robi to na this, niestety nigdzie na zewnatrz nie trzyma referencji do tej instancji wiec sila rzeczy jest skazany na wieczne czekanie...

0

Bardzo dziękuję za dotychczasowe podpowiedzi. Udało mi się wybrnąć z tamtego problemu, jednak teraz pojawił się nowy.

Założenie mam takie, że sterują zapisywaniem i odczytywanie. Wszystko idzie od do pewnego momentu (drugiego powrotu do wątku Weight) - wtedy uruchamia się pierwszy krok (dodanie 300 setnego elementu) jednak próba powrotu do ArrayList powoduje błąd java.util.ConcurrentModificationException.

Poniżej zamieszczam aktualny kod:

 

public class Main {

  public static void main(String[] args)throws InterruptedException  {
  
	  (new Thread(new Wczytywanie())).start();
	 (new Thread(new Weight())).start();
		}
}
 

import java.util.ArrayList;
public class Towary {
int id_towaru;
double waga;
static int countobj = 0;
static int notifnewobj = 100;
static int notifnewweight = 100;
public static ArrayList<Towary> listatowarow = new ArrayList<Towary>();

public Towary(int id_towaru, double waga){
	this.id_towaru = id_towaru;
	this.waga=waga;
	countobj ++ ;
}
void add(int a, double b){
	listatowarow.add(new Towary(a, b));
}
public static int countob(){
	return countobj;
}

double returnweight(){
	return waga;
}

}


import java.io.File;
import java.util.Scanner;
import java.io.FileNotFoundException;
public class Wczytywanie implements Runnable {
	public static boolean state = false;
static int count = 0;
public static int actuallines = -1;
	
	public void run() {

	

		  Scanner s;
		try {

			s = new Scanner(new File("C:/Users/Janusz/Desktop/Towary.txt"));
			synchronized (Towary.listatowarow){
				
			while (s.hasNext()){
				if (count - Weight.counter > 299){
					state = true;
			Towary.listatowarow.notifyAll();
				}
				while (state){
					try {
						Towary.listatowarow.wait();
				      } catch(InterruptedException exc) {}
				}
					
				count ++;
				String[] data = s.nextLine().split("\\s+"); 
				
			Towary.listatowarow.add(new Towary(Integer.parseInt(data[0]), Double.parseDouble(data[1])));
			if(Towary.countob() % Towary.notifnewobj == 0){
				System.out.println("utworzono " + Towary.countob() + " obiektów");
			}
				
			

				
				}
				
			actuallines = Towary.countob();
			s.close();
			state = true;
			Towary.listatowarow.notifyAll();
			System.out.println("-------------/n TOTAL : utworzono " + Towary.countob() + " obiektów");
			}
		} catch (FileNotFoundException e) {
			}
		}

}


public class Weight implements Runnable{

static double actualweight;
static int counter = 0;
boolean finish = false;
public void run(){
	
	
	synchronized (Towary.listatowarow){
		while(!(Wczytywanie.state))
{

	try {
		Towary.listatowarow.wait();
      } catch(InterruptedException exc) {}
}

	for (Towary t : Towary.listatowarow){
		while((counter == (Towary.countob()-1)))
		{
			Wczytywanie.state = false;
			Towary.listatowarow.notifyAll();
			try {
				
				Towary.listatowarow.wait();
				
		      } catch(InterruptedException exc) {}
				
		}
		counter++;
		actualweight= actualweight + t.returnweight();
		
		if(counter % Towary.notifnewweight == 0){
			System.out.println("zważono " + counter + " obiektów");
		}
	}
	}


	System.out.println ("policzono wage " + Towary.countob() +" towarów");
	System.out.println("-------------/n TOTAL : waga " + actualweight);
}
}

Bardzo proszę o dalszą pomoc. W czym leży błąd? Zadanie wydaje się być proste ale czas na nim spędzony spowodował straszny mętlik.

0

dodajesz nowe elementy do

Towary.listatowarow

w trakcie iterowania po niej na innym watku, wbrew temu co oczekujesz iterator nie jest w stanie tego obsluzyc. nie wiem co chcesz osiagnac, ale najprawdopodobniej potrzebujesz wspolbieznej kolejki - https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

0

Ale poprzez synchronizację i dodanie wait w momencie iterowania dodawanie nowych pozycji jest zatrzymane. Czy to ma prawo zadziałać? Czy problem polega na nieuśpieniu wątku dodającego pozycje?

0

Albo użyj po prostu CopyOnWriteArrayList

0

Po raz kolejny dzięki za pomoc;)

Konstrukcja programu wynikała z treści zadania, która narzuca mi synchronizowanie i koordynowanie wątków.

Problem w tym programie to "wyprzedzanie czytania z tablicy vs wprowadzanie do tablicy".
Przyjęte założenie chyba nie ma wiele wspólnego z wątkami, bo w praktyce nie działają dwa wątki na raz.

Czy dodanie bloku "synchronized" wymusza na mnie rozwiązanie nie korzystające na raz z jednego objektu?

Czy może rozwiązać problem na zasadzie - jeśli wątek odczytujący zbliża się do zapisy to jest na x cykli usypiany (wait)?

Z góry dziękuję za dalsze wsparcie.

0

Czy prowadzisz wewnętrzny monolog tymi postami ?? czytasz co inni ci piszą ?

Czy może rozwiązać problem na zasadzie - jeśli wątek odczytujący zbliża się do zapisy to jest na x cykli usypiany (wait)?

Jak wspomniaŁA @katelx użyj https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

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