Problemy z wątkami

0

Witam
Dopiero się uczę podstaw Javy, zacząłem ogarniać watki, napisałem prosty program do poeksperymentowania, ogólnie działa jednak nie do końca jak bym się tego spodziewał. w związku z czym mam parę pytań.

Kod mego programiku:

import java.util.Scanner;


 class Fibonaci {

	
	
	static long fibon(long n)
	{
		if (n<2)
			return n;
		else
			return (fibon(n-1)+fibon(n-2));
		
	}
	

}

 class wateki  implements Runnable {
Thread thrd;

wateki( String nazwa)
{
thrd=new Thread(this, nazwa);

}
public void run()
{
	System.out.println(thrd.getName()+" rozpoczyna działanie");
	System.out.println("podaj wartość dla "+ thrd.getName());
	Scanner w = new Scanner (System.in);
	long wartosc=w.nextLong();
	System.out.println("wynik pracy "+thrd.getName()+"  to "+ Fibonaci.fibon(wartosc));
}

}

	public class watek
	{
		public static void main(String[] args)
		{
			wateki potomny1=new wateki("potomek1");
			wateki potomny2=new wateki("potomek2");
			wateki potomny3=new wateki("potomek3");
			wateki potomny4=new wateki("potomek4");
			
			potomny1.thrd.setPriority(Thread.NORM_PRIORITY-5);
			potomny2.thrd.setPriority(Thread.NORM_PRIORITY-1);
			potomny3.thrd.setPriority(Thread.NORM_PRIORITY+4);
			potomny4.thrd.setPriority(Thread.NORM_PRIORITY+5);
			
			potomny1.thrd.start();
			potomny2.thrd.start();
			potomny3.thrd.start();
			potomny4.thrd.start();
		}
	}

Pytanie nr 1:
Komunikaty z prośbą o wpisanie wartości i z informacją o rozpoczęciu wątku na konsoli wyświetlają się tak jak by w chaotycznej kolejności co mnie nie dziwi, problem zaczyna się już po wyświetleniu wszystkich komunikatów gdy wątki zaczynają oczekiwać na wartości, mianowicie gdy kolejno podaje pierwszą, drugą, trzecią wartość nic się nie liczy dopiero po podaniu czwartej wartości gdy wszystkie wątki otrzymają wartość, rozpoczynają obliczenia jednocześnie, tak jak by czekały na siebie. Spodziewałem się raczej że pojedyncze wątki ruszą gdy otrzymają dla siebie wartość.
//widzę to po obciążeniu procesora.
Pytanie nr 2
Tutaj mam problem z priorytetami, nadałem wątką priorytety jednak pomimo tego wyniki są wyświetlane nie koniecznie z tymi priorytetami, na domiar tego gdy podawałem wartość 50 co zajmowało memu procesorowi około minuty to i tak wyniki były wyświetlane niemal że jednocześnie, powinny być chyba zauważalne odstępy czasu?
Pytanie nr 3
Liczbę wątków w programie zwiększyłem do czterech tak aby w pełni obciążyć mój czerto rdzeniowy Athlon, i tak jak był jeden watek to obciążenie w trakcie wykonywania było ok 27 %, dla dwóch wątków to trochę ponad 50 %.etc, co wydaje mi się zrozumiałe (cztery rdzenie=cztery wątki), tylko przy jednym wątku raczej się spodziewałem niemal całkowitego obciążenie pojedynczego rdzenia, ale jak się okazało w trakcie wykonywania pojedynczego wątku wszystkie rdzenie były wykorzystywane mniej więcej po równo.

Program napisałem w Eclipse dla Windows 7

0

popraw formatowanie, bo losowa ilość spacji i enterów w losowych miejscach plus literówki nie wpływają dobrze na czytelność kodu.

Ad 1. nie znam javy, więc nie znam technicznych szczegółów takiego zachowania, znam jedną zasadę. mówi ona, że wątki nie komunikują się bezpośrednio z użytkownikiem, tj. nie dotykają się do gui/konsoli, a już broń Boże nie robią tego bez jakiejkolwiek synchronizacji. wyobraź sobie taką sytuację, że na wpisanie tekstu w tej samej kontrolce/konsoli czekają jednocześnie dwa wątki. coś piszesz, a litery wpadają w losowej kolejności do obu wątków. naciskasz enter. wpada również do losowego wątku. tak się nie robi i już. jeśli już się uprzesz, to zamknij blok kodu odpowiedzialny za wczytanie tekstu w klauzuli synchronized.
jeśli chcesz mieć to zrobione dobrze, to zrób klasę z obsługującą kolejkę z synchronizowanym dostępem do danych, utwórz wątki w dowolnej ilości i każ każdemu z nich czekać na dane w kolejce, a w głównym wątku programu wczytaj liczby i dodaj je do tej kolejki. wątki (pukają do drzwi) czekają na jakimś muteksie albo czymś podobnym (ponownie kłania się synchronized) na dane w "kolejce" (czekają na otwarcie drzwi), a kiedy dane się pojawiają (drzwi się otwierają), to wątki pojedynczo pobierają porcje danych (przez drzwi wchodzi jeden wątek, bierze stuff, wychodzi i drzwi się zamykają). pozostałe wątki czekają w "kolejce" na kolejne dane (na kolejne otworzenie drzwi). wątek który dostał dane i skończył je przetwarzać wraca do "kolejki" (kolejka w cudzysłowie, bo kolejność w niej nie ma znaczenia, w teorii możliwe jest, żeby dane dostawał cały czas tylko jeden i ten sam wątek, oczywiście o ile nowe dane przyjdą w momencie, kiedy wątek skończy przetwarzać poprzednie dane).
Ad 2. jeden wątek może pracować naraz tylko na jednym rdzeniu, więc pozostałe rdzenie są wolne dla pozostałych wątków. dlatego jeśli masz cztery rdzenie i cztery wątki, to będą się wykonywać równolegle niezależnie od priorytetu i skończą mniej-więcej w tym samym momencie. system przydziela wątkowi ten rdzeń, który akurat mu pasuje i to nie raz na zawsze, tylko raz na dany kwant czasu, chyba że zdefiniujesz odpowiednią regułę (processor affinity). mojemu systemowi akurat pasuje wykonywanie jednego wątku na tym samym rdzeniu, głównie pierwszym, jeśli jest zajęty, to pracuje losowy z kolejnych, a jeśli pracują wszystkie cztery, to dowala część roboty "rdzeniom" HT.
Ad 3. jeden wątek - jeden rdzeń, łącznie cztery rdzenie i pełne obciążenie jednego -> 25%. dodatkowe kilka procent pochodzi od innych programów. to samo tyczy się dwóch wątków (2/4 => 50%) itp. tak jak napisałem, jeśli nie przypiszesz wątku do rdzenia (tzn. na poziomie winapi możesz wybrać, który wątek na których rdzeniach może się wykonywać), to system przyznaje go wedle uznania.

0

Stworzenie oddzielnej klasy z pojedynczą metodą odpowiedzialna za informowanie o rozpoczęciu wątku oraz jednocześnie wczytanie danych i zadeklarowanej jako synchronized static, rozwiązało problem z równoczesnym rozpoczynaniem obliczeń przez wątki i chaosem na konsoli.

Klasa z metodą:

class Interfejs
 {
 	synchronized static long start( String name)
 	{
 	 System.out.println(name +"rozpocyna działanie");
 	 System.out.println("podaj warosc dla "+name);
  
 	 Scanner w = new Scanner (System.in);
         long wartosc=w.nextLong();
         return wartosc;

Wywołanie metody w klasie wątku w metodzie run():

long wartosc=Interfejs.start(thrd.getName());

Dzięki za objaśnienie paru kwestii!

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