Java Threads, gemeinsamer Speicher

Hey, danke für die Infos, aber das umgeschriebene Programm führt immer noch nicht zum richtigen Ergebnis.
Wünschenswert meinerseits wäre, dass die 3 Threads, die ich starte, auf eine gemeinsame Map zugreifen und mehr oder weniger nacheinander einen Eintrag der Map nehmen, ausgeben und löschen.
Momentan bewältigt allerdings immer nur Thread 1 oder Thread 2 diese Aufgabe, Aufgabenteilung findet - wie ich das sehen - nicht statt.
Dummerweise komm ich nicht dahinter, woran genau das liegt, hab schon mehere Dinge ausprobiert.

Danke fürs Helfen schonmal.

Hier nochmal der jetztige Code

Code:
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class Test
{
	   public static void main( String[] args )
	   {
		  HashMap<Integer, String> hashMap = new HashMap<Integer, String>();
		  int count = 100;
		  for(int i = 1; i <= count; i++)
			  hashMap.put(i, Integer.toString(i));
		  
		  Map map = Collections.synchronizedMap(hashMap);			  
		   
	      (new Testobject( 1, map )).start();
	      (new Testobject( 2, map )).start();
	      (new Testobject( 3, map )).start();
	   }
}

Java:
import java.util.Map;

class Testobject extends Thread
{
	   int num;
	   int i = 1;
	   Map map = null;
	   
	   Testobject( int num, Map map)
	   {
	      this.num = num;
	      this.map = map;
	   }

	   @Override
	   public synchronized void run()
	   {
		   synchronized(map) {
			   while(!map.isEmpty()) {				 
				  if(map.get(i) != null) {
					  System.out.println("Thread " + num + ": " + map.get(i));
					  map.remove(i);
					  i++;
					  try { Thread.sleep( 100 ); } catch( InterruptedException ex ) {}
				  }				  
			   }
		   }
	   }
}
 
Naja weil durch das synchronized nur ein Thread auf das Objekt überhaupt zugreifen darf.
Mal schemahaft beschrieben:
Deine von Thread eberende Klasse erhält im Konstruktor eine Referenz auf Test. In Test bastelst du dann eine synchronized get-Methode die den Aufruf auf die Map regelt. Dann erstellst du die threads und übergibst anstatt der Map selbst die Referenz von Test mithilfe von this. Das ist das was ich ganz oben schon mal beschrieben habe : nicht das Objekt selbst übergeben sondern eine Referenz auf this und dann über Getter- und Setter-Methoden zugreifen. Diese natürlich synchronized machen.
 
Ok, dann hab ich dich oben wohl falsch verstanden, ich hoffe, damit hauts jetzt hin.
Danke nochmal, ich werde es demnächst versuchen, so umzusetzen.
 
Puh, ich glaube, jetzt läuft es so, wie ich es wollte, danke für die Hilfe.
Hier nochmal mein Code, etwas erweitert, unter anderem mit Fehlerüberprüfung.
Zwei Dinge haben noch zusätzlich gefehlt, zum Einen musste der i-Counter ebenfalls in das Testobject und zum Anderen noch ein Zugriffstoken.

Code:
public class TestMain {

	public static void main(String[] args) {
		Test test = new Test();
		test.setMap();
		test.startTest();
		while(test.getFinished() != 3) {			
		}
		test.setError();
		if(test.getError() == 0)
			System.out.println("--- Keine Fehler ---");
		else
			System.out.println("Fehler: " + test.getError() + " ... Mist!");
		
	}
}
Code:
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class Test
{
	
	public Test() { }
	
	public synchronized void startTest() {
		(new Testobject( 1, this )).start();
	    (new Testobject( 2, this )).start();
	    (new Testobject( 3, this )).start();
	}
	
	private Map map = null;	
	private int i = 1;
	private boolean block = false;
	private int count = 1000;
	private int finished = 1;
	private int err = 0;
	
	public int getI() { return i; }
	public void setIpp() { i++; }
	
	public synchronized String getMap(int i) { 
		return (String) map.get(i);
	}
	
	public synchronized boolean getBlock() { return block; }
	
	public synchronized void setBlock(boolean block) { this.block = block; }
	
	public synchronized void setMap() { 	
		HashMap<Integer, String> hashMap = new HashMap<Integer, String>();
	  	for(int i = 1; i <= count; i++)
		  hashMap.put(i, Integer.toString(i)); 
	  	  map = Collections.synchronizedMap(hashMap);
	}
	
	public synchronized void removeMap(int i) {
		map.remove(i);
	}
	
	public synchronized boolean emptyMap() {
		if(!map.isEmpty())
			return false;
		else
			return true;
	}
	
	public void finishedPP() { finished++; }
	public int getFinished() { return finished; }
	
	//Fehlerüberprüfung
	private int[] testArray = new int[count];
	private int x = 0;
	public synchronized void addToTestArray(int i) { 
		testArray[x] = i; 
		x++; 
	}
	
	public void  setError() {		
		for(int j = 0; j < count; j++)
			for(int k = 0; k < count; k++)
				if(testArray[j] == testArray[k])
					if(j != k)
						err++;
	}
	
	public int getError() { return err; }

}
Code:
import java.util.Map;

class Testobject extends Thread
{
	   int num;
	   Test test;
	   boolean finished = false;
	   
	   Testobject( int num, Test test) {
	      this.num = num;
	      this.test = test;
	   }

	   public synchronized void run() {
		   while(!test.emptyMap()) {
			   if(!test.getBlock()) {
				   test.setBlock(true);
				   System.out.println("Thread " + num + ": " + test.getMap(test.getI()));
				   test.addToTestArray(test.getI());
				   test.removeMap(test.getI());
				   test.setIpp();
				   test.setBlock(false);
			   }
			   try { Thread.sleep( 10 ); } catch( InterruptedException ex ) {}			   
		   }
		   test.finishedPP();
	   }
}
 
Zuletzt bearbeitet:
Hi,

schau mal hier. Über die Klasse AtomicInteger kannst Du das holen und inkrementieren atomar durchführen. Jeder Thread arbeitet dann mit einem eindeutigen Index.

Klasse MyThread:
Java:
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

class MyThread extends Thread {
	private int meineThreadNum;
	
	private AtomicInteger myIndex;
	
	private Map<Integer, String> map = null;

	public MyThread(AtomicInteger index, int meineThreadNum, Map<Integer, String> map) {
		this.meineThreadNum = meineThreadNum;
		this.map = map;
		myIndex = index;
	}

	@Override
	public synchronized void run() {
		while (!map.isEmpty()) {
			int i = myIndex.getAndIncrement();
			if(map.containsKey(i)) {
				System.out.println("Thread " + meineThreadNum + ": " + map.get(i));
				map.remove(i);
			}
		}
	}
}

Klasse Test:
Java:
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
 
public class Test
{
       public static void main( String[] args )
       {
          Map<Integer, String> map = new HashMap<Integer, String>();
          int count = 1000;
          for(int i = 1; i <= count; i++) {
              map.put(i, Integer.toString(i));
          }
          
          AtomicInteger index = new AtomicInteger(1); 
          
          Map<Integer, String> synchronizedMap = Collections.synchronizedMap(map);
          
          (new MyThread(index, 1, synchronizedMap)).start();
          (new MyThread(index, 2, synchronizedMap)).start();
          (new MyThread(index, 3, synchronizedMap)).start();
       }
}

Vielleicht hilft Dir das ja weiter.

Gruß twagi
 
Zurück