alle 100ms Befehle ausführen

Fohnbit

Top Contributor
Hallo Gemeinde!

Wie kann ich Ressourcenschonend Befehle zuerst sammeln und nur alle 100ms ausgeben?
Ich benötige daher ein Array(?) wo ich meine eigenen Anweisungen reinschreibe.
Nehmen wir die Strings:
"45,2324.234354.23,0"
"0,234.23423.1232,11.2"

Nun soll ein Timer zyklisch alle 100ms gestartet werden, sobald der erste Wert in das Array gelegt wird.
Nach 100ms soll er alles absenden, was im Array ist und dieses leeren und auf neue warten.

Es könnte aber sein das, dass während des Senden neue Befehle ins Array kommen. Das soll aber die Abarbeitung nicht stören.

Hintergrund:
Es sollen Daten per UDP versendet werden. Ich möchte aber soviel es geht, sammeln. Damit verhindere ich viele kleine Pakete und 100ms verzögerung ist ok.

Für einen Ansatz wäre ich euch sehr dankbar!

Fohnbit
 

ChristianK

Aktives Mitglied
Ich tippe auf Thread.sleep(), und beachte, eine programmierte Verzögerung von 100ms ist stets >100ms. Jedoch weder berechenbar noch algorhitmysch definiert.

Eventuell wäre es sinnoll, einene seperaten Thread zu erstellen, der nur das Senden im Intervall übernimmt.
 
Zuletzt bearbeitet:

Fohnbit

Top Contributor
Hallo!

Vielen Dank für die Hilfe. Habs mal getested und augenscheinlich paßt es(?).
Wenn nur ein Wert in der Queue liegt, wird das senden um 100ms verzögert. Wenn mehr, wird alles gesendet.
Ich greife jedoch vom Thread aus auf die Variable "queue" zu. Ist das so OK?
Bzw. wir könnte man es sicherer/effizienter machen? Es gibt ja auch einen Notify Befehl. Kann ich den Thread warten lassen damit er nicht immer im Loop läuft?

Java:
public class snmp {

	public static Queue<String> queue = new ConcurrentLinkedQueue<String>();

	public static void main(String[] args) throws IOException {
		Thread thSendSNMP = new sendSNMP();
		thSendSNMP.start();

		queue.offer("test1 " + String.valueOf(System.currentTimeMillis()));
		queue.offer("test2 " + String.valueOf(System.currentTimeMillis()));

		try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		queue.offer("test3 " + String.valueOf(System.currentTimeMillis()));
		queue.offer("test4 " + String.valueOf(System.currentTimeMillis()));
		queue.offer("test5 " + String.valueOf(System.currentTimeMillis()));
		queue.offer("test6 " + String.valueOf(System.currentTimeMillis()));
		queue.offer("test7 " + String.valueOf(System.currentTimeMillis()));
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		queue.offer("test8 " + String.valueOf(System.currentTimeMillis()));
}

public class sendSNMP extends Thread {

	@Override
	public void run() {
		Boolean flush = false;

		while (true) {

			if (!snmp.queue.isEmpty()) {
				// System.out.println("Inhalt: " + snmp.queue.size());
				if (snmp.queue.size() == 1 & !flush) {
					try {
						Thread.sleep(100);
						flush = true;
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				} else {
					flush = true;
					System.out.println("Ausgabe: " + snmp.queue.poll() + " "
							+ String.valueOf(System.currentTimeMillis()));
				}
			} else {
				flush = false;
			}

		}

	}

}
 
Zuletzt bearbeitet:

ChristianK

Aktives Mitglied
Ich verweise einmal hierrauf: https://forum.vis.ethz.ch/showthrea...Thread.sleep()&p=110727&viewfull=1#post110727

.sleep() trifft es für deine Aufgabe besser meiner Einschätzung nach. Mit .wait(object) sagst du ebene explizit, dass du davon abhängig bisst, dass object seine Arbeit erledigt hat. Was dann object wiederum mit .notify() bestätigt.

Die Endlosschleife macht hier nichts aus, der Prozessor kommt damit klar. Sobald du .sleep(n) aufrufst hast du auch keine Chance, innerhalb der Zeitspanne n mit deinem Thread den Prozessor zu belasten.
 

Fohnbit

Top Contributor
Hallo!

Ok, dann belasse ich es mal bei Sleep!

Nun kommt noch ein Punkt hinzu:
In der Queue liegen die Zieladressen inkl. Daten. Diese sollen an die IPv6 Adressen gesendet werden.
Ziel ist es ja, Daten zu sammeln und dann gemeinsam abzusenden.

Jedoch muss ich die Daten Ipv6 mäßig zusammenfassen. Denn wenn ein Befehl an IP1 und ein zweiter an IP2 in der Queue liegen, nützt es nichts beim ersten 100ms zu warten.

Da es n IPv6 Ziele gibt, bräuchte ich theoretisch auch n eigenständige Queue´s. Ist wohl nicht ratsam, oder?
Wie würdet Ihr die Sache umsetzen?

Ein Array wo für jeweils einer IP zusätzliche Infos stehen? Dann müßte die Queue aber immer durchlaufen werden und geprüft werden, für welche IP Daten zum senden bereit stehen.
 

ChristianK

Aktives Mitglied
Wenn die Daten fortlaufend anfallen und du umgehende Versendung wünscht, dann musst du (wohl oder übel) auf das Intervall verzichten. Wenn die Daten stossweise anfallen kannst du ja auch prüfen, welche IP im nächsten Eintrag der Queue ist. Insofern es die gleiche ist, fasst du die Daten zusammen. Ansonsten wartest du 100ms und führst danach den nächsten Eintrag aus.

Bedenke, dass du mit dieser künstlichen Verzögerung (je nach anfallender Daten, Konstellation der Adressen, ...) eine Queue erzeugen könntest, die erst nach langer Zeit fertig abgearbeitet ist. Bei 10 verschiedenen Adressen und der ungünstigsten Konstellation von 3 Datensätzen pro Adresse hättest du zwischen dem 1. Satz an IP 1 und dem letzen 2.9 Sekunden Differenz (bei einer Verzögerung von 100ms).

Edit: Vielleicht wäre es sinnvoller, eine IP-spezifische Queue zu führen: Jede IP besitzt ihre eigene Queue.
 
Zuletzt bearbeitet:

Fab1

Top Contributor
Nur damit es mal noch erwähnt wird. Es gibt auch eine Klasse TimerTask (Java Platform SE 7 ) mit der man entsprechende Verzögerungen sehr leicht umsetzen kann. Ist meines wissens auch genauer als sleep().

Eine andere Möglichkeit wäre natürlich (ka ob der vorredner das meinte) die Befehle zu sammeln und sagen wir mal bei 5 Stück diese auszuführen. So könnte man vermeiden, dass extrem viele Befehle gleichzeitig ausgeführt werden. (Im Fall der Fälle)
 

Fohnbit

Top Contributor
Hallo!

Also ich kann keine Befehle sammeln.
Weiterer Hintergrund: Die Befehle schalten Lichter und fahren Beschattungen. Da ist es egal, ob das Licht 100ms später einschaltet.
Jedoch muss spätestens nach 100ms der Befehl gesendet werden (+/- 50ms)
Ich kann ja den Wert noch auf 70ms runterstellen.

Die Queue durchsuchen und danach auf die IP Adressen aufteilen halte ich nun nicht mehr so effizient.
Jede IP Adresse soll wohl Ihre eigene Queue bekommen.

Aber wie baut man das auf? Die Queue soll dynamisch bleiben. IP Ziele können hinzukommen oder wegfallen im Laufe der Zeit.
Gibt es eine Art "List of Queue"? Wo ich mittels Add Queue´s hinzufügen kann?
Beim senden kann ich dann ja jede Queue durchlaufen lassen und diese absenden. Jede Queue bekommt dann ihren eigenen "Flush Timer".

Danke!
 

Fohnbit

Top Contributor
Hab da mal etwas probiert, läuft aber nicht richtig:

Hier wird die Queue mal gefüllt. Mittels einer Map wird eine neue hinzugefügt, wenn die IP Adresse noch nicht existiert:
Java:
public class snmp {

	static Queue<hostOID> queue = new ConcurrentLinkedQueue<hostOID>();
	// public static ArrayList<Queue> myList = new ArrayList<Queue>();
	@SuppressWarnings("rawtypes")
	public static Map<String, Queue> mapQueue = new HashMap<String, Queue>();

	public static void main(String[] args) throws IOException {
		// OID Sender starten (natürlich leere Queue)
		Thread thSendSNMP = new sendSNMP();
		thSendSNMP.start();

		// hostOID vorbereiten
		hostOID vHostOID = new hostOID();
		vHostOID.community = "private";
		vHostOID.host = "192.168.0.89";
		vHostOID.strOID = ".1.3.6.1.4.1.32111.1.1.2.1";
		vHostOID.Value = 1;
		AddOID(vHostOID);
		
		vHostOID.strOID = ".1.3.6.1.4.1.32111.1.1.2.2";
		AddOID(vHostOID);

		try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		vHostOID.strOID = ".1.3.6.1.4.1.32111.1.1.2.3";
		AddOID(vHostOID);
		vHostOID.strOID = ".1.3.6.1.4.1.32111.1.1.2.4";
		AddOID(vHostOID);
		vHostOID.strOID = ".1.3.6.1.4.1.32111.1.1.2.5";
		AddOID(vHostOID);
		vHostOID.strOID = ".1.3.6.1.4.1.32111.1.1.2.6";
		AddOID(vHostOID);

		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		vHostOID.strOID = ".1.3.6.1.4.1.32111.1.1.2.7";
		AddOID(vHostOID);
	}

	@SuppressWarnings("unchecked")
	private static void AddOID(hostOID vHostOID) {
		// Wenn eine Queue mit dem Host schon existiert, hinzufügen
		if (mapQueue.containsKey(vHostOID.host)) {
			// Es existiert schon eine Queue für diesen Host
			mapQueue.get(vHostOID.host).offer(vHostOID);
			
		} else {
			mapQueue.put(vHostOID.host, new ConcurrentLinkedQueue<String>());
		}
	}
}

public class hostOID {

	public String host;
	public String community;
	public String strOID;
	public int Value;
}

Hier wird nun die Map mit den Queue´s verarbeitet:
Java:
package snmp;

import java.util.HashMap;
import java.util.Map;
import java.util.Queue;

public class sendSNMP extends Thread {

	@Override
	public void run() {
		// Map um zu den Queue einen Flush zu setzen
		Map<String, Boolean> mapFlush = new HashMap<String, Boolean>();

		while (true) {
			// Für jede Queue in der Map mapQueue
			for (Queue<hostOID> queue : snmp.mapQueue.values()) {
				// Prüfen ob die Queue überhaupt Einträge besitzt
				if (!queue.isEmpty()) {
					// Queue hat Einträge und muss geprüft werden, ob zu dem
					// Host schon ein Eintrag in der Map mapFlush existiert
					if (!mapFlush.containsKey(queue.peek().host)) {
						// Noch kein Eintrag in der mapFlush und dadurch einen
						// hinzufügen
						mapFlush.put(queue.peek().host, false);
					}
					// Prüfen ob die Queue mehr als einen Eintrag hat und ob ein
					// Flush erzwungen wird
					if (queue.size() == 1 & !mapFlush.get(queue.peek().host)) {
						// Es ist nur ein Eintrag in der Queue und wird zum
						// ersten mal aufgerufen. Nach der Pause den Flush
						// aktivieren
						// * noch zu programmieren *: Thread.sleep(40);
						// Flush für den Host in der Queue aktivieren
						mapFlush.put(queue.peek().host, true);
					} else {
						// Queue hat mehr als einen Eintrag und kann gesendet
						// werden. Flush ausschalten das er ja gerade ausgeführt
						// wird
						mapFlush.put(queue.peek().host, false);
						System.out.println("Ausgabe: " + queue.poll().strOID + " "
								+ String.valueOf(System.currentTimeMillis()));
					}
				} else {
					// Kein Eintrag in der Queue und dadurch kann er auch der
					// Flush abgeschaltet werden
					// mapFlush.put(queue.peek().host, false);
				}

			}

		}

	}

}

Leider gibt er mir immer nur den letzten Eintrag in der Queue aus. So als ob der .poll() den Eintrag nicht entfernt oder schon zu beginn immer nur ein Eintrag enthalten ist.

Wäre das ein guter Weg und eventuell kann hier den Code etwas "korrigieren" ?

Vielen Dank!
 

Fohnbit

Top Contributor
Ok, einen Fehler gefunden:

Java:
...
vHostOID = new hostOID();
		vHostOID.community = "private";
		vHostOID.host = "192.168.0.84";
		vHostOID.Value = 1;
		vHostOID.strOID = ".1.3.6.1.4.1.32111.1.1.2.5";
		AddOID(vHostOID);

		vHostOID = new hostOID();
		vHostOID.community = "private";
		vHostOID.host = "192.168.0.89";
		vHostOID.Value = 1;
		vHostOID.strOID = ".1.3.6.1.4.1.32111.1.1.2.6";
		AddOID(vHostOID);
...

	@SuppressWarnings("unchecked")
	private static void AddOID(hostOID vHostOID) {

		// Wenn eine Queue mit dem Host schon existiert, hinzufügen
		if (mapQueue.containsKey(vHostOID.host)) {
			// Es existiert schon eine Queue für diesen Host
			Queue<hostOID> qu = mapQueue.get(vHostOID.host);
			qu.offer(vHostOID);
			mapQueue.put(vHostOID.host, qu);
		} else {
			Queue<hostOID> qu = new ConcurrentLinkedQueue<hostOID>();
			qu.offer(vHostOID);
			mapQueue.put(vHostOID.host, qu);
		}
	}

Jedoch scheint das dann nicht Threat sicher? Ich erhalte einen Fehler, wenn "sendSNMP" läuft und ich die Map auch befülle.
Exception in thread "Thread-0" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
at java.util.HashMap$ValueIterator.next(Unknown Source)
at snmp.sendSNMP.run(sendSNMP.java:16)

Lasse ich "sendSNMP" erst starten, wenn alles befüllt ist, läuft es ohne Problem durch!
 

wef34fewrg

Aktives Mitglied
So soll es ja auch sein.

Die geworfene Exception kommt auf, wenn du weil du gerade über eine Datenstruktur läufst, die du währenddessen änderst.

Dies kannst du umgehen in dem du deine Aufgaben nacheinander ablaufen lässt (bspweise. Thread 1 befüllt, warte mit join() aufs Ende und starte Thread 2 etc). Ebenfalls wäre synchronized um die betreffenden Stellen möglich. Beides schränkt natürlich die Parallelität enorm ein bzw. schließt sie aus.

Wenn du unbedingt beides haben willst/musst, solltest du dir die Concurrent-Klassen (ConcurrentHashMap, ConcurrentLinkedQueue etc.) anschauen. Die lösen zumindest das Exceptionproblem.
 
Zuletzt bearbeitet:

Fohnbit

Top Contributor
Hallo!

Danke für die Info!

Also befüllen und senden muss unbedingt unabhängig arbeiten.
Werde nach den Schlagwörtern mal suchen.

Danke!
 
Zuletzt bearbeitet:

Fohnbit

Top Contributor
Hallo!

Also ich habe es mal reingebaut. Funktioniert wohl so wie gewünscht. Aber eventuell hat noch jemand eine Optimierungs Idee?
Ich denk 2 Punkte könnte man noch verbessern?:
a) Die Queue zu befüllen. Zuerst muss ich ja prüfen ob die Queue schon existiert. Wenn ja, ein Objekt davon erstellen, den neuen Eintrag hinzufügen und wieder in die Map legen
b) Die Sleep Funktion habe ich nun mit einem Timer und einem Boolean Wert realisiert. Was wäre aber wenn ich zu den Einträgen einen Timestamp mitschreibe? Dann könnte ich prüfen, ob der aktuelle Timestamp 100ms nach dem 1. Eintrag liegt. Problem ist aber, wenn gesendet und die lokale Uhrzeit angepasst wird :) Auch Schaltjahre können Probleme machen.

Danke!

Java:
public class snmp {

	static Queue<hostOID> queue = new ConcurrentLinkedQueue<hostOID>();
	@SuppressWarnings("rawtypes")
	public static Map<String, Queue> mapQueue = new ConcurrentHashMap<String, Queue>();

	public static void main(String[] args) throws IOException {
		// OID Sender starten (natürlich leere Queue)
		Thread thSendSNMP = new sendSNMP();
		thSendSNMP.start();

		// hostOID vorbereiten
		hostOID vHostOID = new hostOID();
		vHostOID.community = "private";
		vHostOID.host = "192.168.0.89";
		vHostOID.Value = 1;
		vHostOID.strOID = ".1.3.6.1.4.1.32111.1.1.2.1";
		vHostOID.Milli = System.currentTimeMillis();
		AddOID(vHostOID);

...

...

private static void AddOID(hostOID vHostOID) {

		// Wenn eine Queue mit dem Host schon existiert, hinzufügen
		if (mapQueue.containsKey(vHostOID.host)) {
			// Es existiert schon eine Queue für diesen Host
			@SuppressWarnings("unchecked")
			Queue<hostOID> qu = mapQueue.get(vHostOID.host);
			qu.offer(vHostOID);
			mapQueue.put(vHostOID.host, qu);
		} else {
			Queue<hostOID> qu = new ConcurrentLinkedQueue<hostOID>();
			qu.offer(vHostOID);
			mapQueue.put(vHostOID.host, qu);
		}
	}

Java:
public class sendSNMP extends Thread {

	@Override
	public void run() {
		// Map um zu den Queue einen Flush und "Sleep" zu setzen
		final Map<String, FlushMap> mapFlush = new ConcurrentHashMap<String, FlushMap>();
		Timer timer = new Timer();
		while (true) {

			// Für jede Queue in der Map mapQueue
			for (final Queue<hostOID> queue : snmp.mapQueue.values()) {

				// Prüfen ob die Queue überhaupt Einträge besitzt
				if (!queue.isEmpty()) {
					/*
					 * Queue hat Einträge und muss geprüft werden, ob zu dem
					 * Host schon ein Eintrag in der Map mapFlush existiert
					 */
					if (!mapFlush.containsKey(queue.peek().host)) {
						/*
						 * Noch kein Eintrag in der mapFlush und dadurch einen
						 * hinzufügen
						 */

						mapFlush.put(queue.peek().host, new FlushMap());
					}

					/*
					 * Prüfen ob die Queue mehr als einen Eintrag hat und ob ein
					 * Flush erzwungen wird
					 */
					if (queue.size() == 1
							& !mapFlush.get(queue.peek().host).flush) {
						/*
						 * Es ist nur ein Eintrag in der Queue und wird zum
						 * ersten mal aufgerufen. Flush auf true setzen und
						 * Pause auf True setzen.
						 */
						mapFlush.put(queue.peek().host,
								new FlushMap(true, true));

						timer.schedule(new TimerTask() {
							@Override
							public void run() {
								mapFlush.put(queue.peek().host, new FlushMap(
										true, false));
							}
						}, 500);

					} else if (!mapFlush.get(queue.peek().host).waitFlush) {
						/*
						 * Queue hat mehr als einen Eintrag und kann gesendet
						 * werden. Flush ausschalten das er ja gerade ausgeführt
						 * wird.
						 */
						mapFlush.put(queue.peek().host, new FlushMap());
						System.out.println("Ausgabe: "
								+ queue.peek().host
								+ ":"
								+ queue.peek().strOID
								+ " "
								+ String.valueOf(System.currentTimeMillis()
										- queue.poll().Milli));
					}
				}

			}

		}

	}

}
 

ChristianK

Aktives Mitglied
Ich habe noch nie mit TimerTask gearbeitet... Für mich sieht die Funktionsweise, die du hier implementiert hast, jedoch stark nach Rekursiv aus. Deshalb hätte ich hier wirklich das Thread.sleep() bevorzugt... Ein Thread, der die Queue befüllt und einer, der sie versendet.

Dann gäbe es wohl folgende Klassen bei mir:
- MyQueue
- Filler
- Writer
- HeadControl

HeadControl erstellt einen Filler-Thread und einen Writer-Thread, wobei bei MyQueue als Parameter bekommen. Dann können beide darauf zugreifen und damit arbeiten. Und einfach nicht vergessen, die Threads zu synchronisieren: Der Filler darf in der Zeit, in der der Writer auf die Queue zugreift nicht auch darauf zugreifen...
 

kay73

Bekanntes Mitglied
Nun geb' ich auch meinen Senf dazu:

Du willst Consumer/Producer implementieren. Der Code unten erzeugt bei 3 Hosts und mehr als 1000 Nachrichten pro Host im Mittel bei 100 Millisekundenintevallen gerade einmal 1 ms Versatz und hat keine Synchronisationsprobleme.

  • Der
    Code:
    MessageProducer
    erzeugt in kleinen Zeitabständen für einen zufälligen
    Code:
    Host
    eine zufällige
    Code:
    Message
    . Letztere beide sind Dummyklassen, die einen String kapseln und die du beliebig erweitern und anpassen kannst.
  • Nutze für jeden Host eine
    Code:
    java.util.concurrent.LinkedBlockingQueue
    , in der der Producer die Messages ablegt und der Consumer die Messages ausliest. Diese Klasse ist genau dafür gemacht und löst die Synchronisationsprobleme, die oben angesprochen wurden.
  • Jeder Host erhält genau einen Consumer in einem eigenen Thread (siehe DispatchDemo.onNewHost). Frage im Consumer die Queue mittels
    Code:
    drainTo
    alle 100ms ab. Hier wird der Versand der Nachrichten an eine (Beispiel-)Klasse MessageListener delegiert.
    Die innere Schleife sieht so aus:
    Java:
    while(!Thread.interrupted()) {								
    			final List<Message> messages = new ArrayList<>(DEFAULT_MESSAGE_ARRAYSIZE);
    			queue.drainTo(messages);		
    			
    			if(!messages.isEmpty()) {
    				messageListener.onMessages(host, messages);				
    			}
    			Thread.sleep(100);
    		}
  • Nutze
    Code:
    ExecutorService
    und Callables. Es macht kaum noch Sinn, Threads "per Hand" zu erzeugen.

Java:
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;

class Host {
	String ip;

	public Host(String ip) {
		super();
		this.ip = ip;
	}

	@Override
	public String toString() {
		return "Host [" + (ip != null ? "ip=" + ip : "") + "]";
	}
}

class Message {
	String message;

	public Message(String message) {
		super();
		this.message = message;
	}

	@Override
	public String toString() {
		return "Message [" + (message != null ? "message=" + message : "")
				+ "]";
	}
}

interface HostListener<T>{
	void onNewHost(final Host host, final BlockingQueue<T> queue);
}

interface MessageListener {
	void onMessages(final Host host, final List<Message> messages);
}

class MessageConsumer implements Callable<Void> {
	
	private static final Logger logger = Logger.getLogger(MessageConsumer.class.getName());
	
	private static final int DEFAULT_MESSAGE_ARRAYSIZE = 100;
	
	private Host host;
	private BlockingQueue<Message> queue;
	private MessageListener messageListener;

	public MessageConsumer(Host host, BlockingQueue<Message> queue,
			MessageListener messageListener) {
		super();
		this.host = host;
		this.queue = queue;
		this.messageListener = messageListener;
	}

	@Override
	public Void call() throws Exception {
		while(!Thread.interrupted()) {								
			final List<Message> messages = new ArrayList<>(DEFAULT_MESSAGE_ARRAYSIZE);
			queue.drainTo(messages);		
			
			if(!messages.isEmpty()) {
				logger.log(Level.FINER, "Dispatching {0} messages to host {1}", new Object [] {messages.size(), host});
				messageListener.onMessages(host, messages);				
			}
			Thread.sleep(100);
		}
		return null;
	}
}

class MessageProducer implements Callable<Void> {
	
	private static final Logger logger = Logger.getLogger(MessageProducer.class.getName());
	
	private static final int NUM_MAXMESSAGES = 10000;
	
	private final Map<Host, BlockingQueue<Message>> hostQueueMap;
	private final HostListener<Message> hostListener;
	
	final Host [] hosts = {new Host("google"), new Host("amazon"), new Host("java-forum")};		
	final String [] messages = {"start", "stop", "burn"};
	final Random random = new Random();		

	public MessageProducer(Map<Host, BlockingQueue<Message>> hostQueueMap,
			HostListener<Message> hostListener) {
		super();
		this.hostQueueMap = hostQueueMap;
		this.hostListener = hostListener;
	}

	private void dispatch(final Host host, final Message message) throws InterruptedException {
		BlockingQueue<Message> queue = hostQueueMap.get(host);
		if(queue == null) {
			queue = new LinkedBlockingQueue<>();
			hostQueueMap.put(host, queue);
			hostListener.onNewHost(host, queue);				
		}
		
		queue.put(message);
	}

	@Override
	public Void call() throws Exception {
		while(!Thread.interrupted()) {	
			final int numMessages = random.nextInt(NUM_MAXMESSAGES) + 1;
			for(int i=0; i < numMessages; i++) {
				
				final Host host = hosts[random.nextInt(hosts.length)];
				final Message msg = new Message(messages[random.nextInt(messages.length)]);
				dispatch(host, msg);
				
				logger.log(Level.FINEST, "Created message {0} for host {1}", new Object [] {host, msg});
			}
			Thread.sleep(10);
		}
		return null;
	}		
};

public class DispatchDemo implements HostListener<Message>, MessageListener {
	
	private static final Logger logger = Logger.getLogger(DispatchDemo.class.getName());
	
	private Map<Host, BlockingQueue<Message>> hostQueueMap = Collections.synchronizedMap(new HashMap<Host, BlockingQueue<Message>>());
	
	private ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
	
	void start() {
		newCachedThreadPool.submit(new MessageProducer(hostQueueMap, this));
		logger.info("started.");
	}
	
	@Override
	public void onNewHost(Host host, BlockingQueue<Message> queue) {
		logger.log(Level.INFO, "adding queue for new host: {0}", host);
		newCachedThreadPool.submit(new MessageConsumer(host, queue, this));		
	}
	
	@Override
	public void onMessages(Host host, List<Message> messages) {
//		logger.log(Level.INFO, "Sending {0} messages to {2}: ({1}) .", new Object[]{messages.size(), messages, host});
		logger.log(Level.INFO, "Sending {0} messages to {2}.", new Object[]{messages.size(), messages, host});
	}
	
	public static void main(String[] args) throws InterruptedException {
		
		System.setProperty("java.util.logging.SimpleFormatter.format", "[%1$tH:%1$tM:%1$tS:%1$tL] %4$s: %5$s%n");
		DispatchDemo dispatchDemo = new DispatchDemo();
		dispatchDemo.start();
		
		Thread.sleep(1000000);
	}
}
 
Zuletzt bearbeitet:

Fohnbit

Top Contributor
Hallo Kay!

Oh, Super! Dank dir.
Ich muss erst noch deinen Code studieren, jedoch habe ich in der Zwischenzeit herausgefunden, dass ich noch den Timestamp benötige.

Es soll ja versucht werden, Pakete zu sammeln und dann auf einmal zu versenden.
Bei einer starren zyklischen Schleife mit 100ms kann es natürlich passieren, dass gesendet wird, wenn nur ein Befehl in der Queue liegt und in 5ms der nâchste kommen würde.

Wenn ich also den Timestamp setze, kann ich folgendes machen:
Prüfe auf einen Eintrag in der Queue, wenn ja:
Prüfe ob sich der Timestamp 100ms hinter dem Atuellen liegt und wenn nein:
Sleep mit der Zeit in Millisekunden
Sonst gleich absenden.

So wird "genau" nach dem ersten Eintrag 100ms gewartet und dann alles gesendet, was in der Wartezeit noch in die Queue gelegt wird.

Was hältst du von der Idee?

Danke an alle! Schöne Feiertage!
 

Fohnbit

Top Contributor
Hallo Kay!

Ich habe nun mal deinen Code studiert und so einigermaßen begriffen.
Ich habe nun folgendes eingebaut:
Für die Queue wird anhand vom 1. Eintrag ein Sleep von 100ms erzeugt. Jedoch je nachdem wie alt der Eintrag ist:
Java:
class Message {
	String message;
	Long timeStamp;

	public Message(String message, Long timeStamp) {
		super();
		this.message = message;
		this.timeStamp = timeStamp;
	}
	
	@Override
	public String toString() {
		return "Message [" + (message != null ? "message=" + message : "")
				+ "]";
	}
}

class MessageProducer
Java:
    @Override
    public Void call() throws Exception {
        while(!Thread.interrupted()) { 
            final int numMessages = random.nextInt(NUM_MAXMESSAGES) + 1;
            
            for(int i=0; i < numMessages; i++) {
               
                final Host host = hosts[random.nextInt(hosts.length)];
                final Message msg = new Message(messages[random.nextInt(messages.length)], System.currentTimeMillis());
                dispatch(host, msg);
               
                logger.log(Level.FINEST, "Created message {0} for host {1}", new Object [] {host, msg});
            }
            Thread.sleep(10);
        }
        return null;
    }

class MessageConsumer
Java:
public final int DEFAULT_SLEEP_TIME = 100;

@Override
	public Void call() throws Exception {
		while (!Thread.interrupted()) {
			final List<Message> messages = new ArrayList<>(
					DEFAULT_MESSAGE_ARRAYSIZE);

			long timeStamp = getSleep((queue.peek().timeStamp != null ? queue
					.peek().timeStamp : 0));

			logger.log(Level.INFO, "TimeStamp: " + timeStamp + " for Host "
					+ host);
			Thread.sleep(timeStamp);

			queue.drainTo(messages);

			if (!messages.isEmpty()) {
				logger.log(Level.INFO,
						"Dispatching {0} messages to host {1}", new Object[] {
								messages.size(), host });
				messageListener.onMessages(host, messages);
			}
			// Thread.sleep(100);

		}
		return null;
	}

	private long getSleep(long timeStamp) {
		long timeSpan = System.currentTimeMillis() - timeStamp;
		if (timeSpan > 0 && timeSpan < DEFAULT_SLEEP_TIME) {
			return timeSpan;
		}
		return 0;

	}

Kann man eventuell den Sleepwert zu errechnen, einfach machen?

Auch muss ich mir noch überlegen, was passiert wenn Netzwerkseitig das versenden in einen TimeOut laufen würde. Aber wiederum mit eigenständigen Thread's sollte das kein Problem sein, oder?

Danke an alle!
 

Fohnbit

Top Contributor
Habs noch etwas geändert.
22.000 Messages werden nun unter 1sek auf 200-300 Messagepakete gesendet:
Java:
@Override
	public Void call() throws Exception {
		while (!Thread.interrupted()) {
			final List<Message> messages = new ArrayList<>(
					DEFAULT_MESSAGE_ARRAYSIZE);

			if (!queue.isEmpty()) {
				long timeStamp = getSleep(queue.peek().timeStamp);
				logger.log(Level.FINEST, "TimeStamp: " + timeStamp
						+ " for Host " + host);
				Thread.sleep(timeStamp);

				queue.drainTo(messages);
				logger.log(Level.FINEST,
						"Dispatching {0} messages to host {1}", new Object[] {
								messages.size(), host });
				messageListener.onMessages(host, messages);
			}

			// Thread.sleep(100);

		}
		return null;
	}

	private long getSleep(long timeStamp) {
		long timeSpan = System.currentTimeMillis() - timeStamp;
		if (timeSpan > 0 && timeSpan < DEFAULT_SLEEP_TIME) {
			return DEFAULT_SLEEP_TIME - timeSpan;
		}
		return 0;

	}
 

kay73

Bekanntes Mitglied
Java:
@Override
	public Void call() throws Exception {
		...
				long timeStamp = getSleep(queue.peek().timeStamp);
				...
	}
Vorsicht:
Code:
queue.peek()
kann null zurückgeben, oder je nach Implementierung kann eine Exception fliegen.

IMHO ist der gemerkte Timestamp an einer Message Daten-Ballast, denn es genügt doch der Zeitpunkt des letzten Absendens einer Nachricht. Ich habe eine Klasse
Code:
FasterMessageConsumer
von
Code:
MessageConsumer
abgeleitet, deren inneren Schleife aufwacht, wenn ein Element zur Queue hinzugefügt wurde. Wenn zwischen den Zeitpunkt des letzten Versands weniger Zeit als die "Schlafenszeit" vergangen ist, legt sich der Thread noch etwas schlafen und macht erst dann sein drainTo.

Code habe im ZIP-File angehängt.

Hier ist die Schleife:
Java:
@Override
	public Void call() throws Exception {
		
		long lastTransmission = System.currentTimeMillis();
		while(!Thread.interrupted()) {								
			
			final Message take = queue.take();
			final long idleTime = System.currentTimeMillis() - lastTransmission;
			
			if(idleTime < DEFAULT_SLEEPTIME_MS) {
				Thread.sleep(DEFAULT_SLEEPTIME_MS - idleTime);
			
			}
			final List<Message> messages = new ArrayList<>(DEFAULT_MESSAGE_ARRAYSIZE);
			messages.add(take);
			queue.drainTo(messages);		
			
			logger.log(Level.FINER, "Dispatching {0} messages to host {1}", new Object [] {messages.size(), host});
			messageListener.onMessages(host, messages);				
			lastTransmission = System.currentTimeMillis();		
		}
		return null;
	}
 

Anhänge

  • DispatchDemo.zip
    1,8 KB · Aufrufe: 5

Fohnbit

Top Contributor
Hallo Kay!

Vielen Dank!
Ich muss erst noch den Code einbauen und meine Vermutung prüfen, aber ist es nicht so, dass er dann bei jeder Nachricht den Sleep ausführt?
Er soll ja nur vom ersten Eintrag in der Queue die Sleep Zeit berechnen.

Könnte man nicht "einfach" die Queue Klasse überschreiben und einen Timestamp dort hinzufügen?
Dann wird dieser immer aktualisiert, wenn der erste Eintrag hinzukommt.

Schöne Grüße und schöne Feiertage!

Hannes
 

Fohnbit

Top Contributor
Nochmals Hallo!

Ich habe deinen Code eingaut und funktioniert natürlich :)

Jedoch würde ich gerne einen Punkt noch ändern. Ich möchte gerne den Timestamp beim Erzeugen der Message schon setzen und davon die 100ms berechnen.
Auch muss ich aus der DispatchDemo die Messages und Hosts übergeben.
Was mir Sonderbar auffältt:
Die Methode ".isEmpty()" springt für den selben Host teilweise 4x hintereinander an. Da es auch jeweils 4 verschiedene Threads sind, erkläre ich mir das so, dass die Threads fast zur selben zeit ausgeführt werden und in der Zeile 42 ("if (queue.isEmpty())") alle 4 noch leer sind.
Oder habe ich irgendwo einen Fehler?

Habs mal alles angehängt!

Danke!
 

Anhänge

  • Dispatch.zip
    4,2 KB · Aufrufe: 2
Zuletzt bearbeitet:

kay73

Bekanntes Mitglied
Hallo Fohnbit,

ich hoffe ich habe Deine Anforderungen richtig verstanden.

Wenn eine "Signalquelle" Nachrichten in zufälligen Abständen produziert, und man diese "bündeln" möchte, muss man sich überlegen, welche Bedingungen bei der Bündelung gelten sollen. Die einzige Bedingung, die der FasterMessageConsumer erfüllt ist die, dass eine Nachricht maximal 100ms Verspätung hat. Dabei lässt sich nicht vermeiden, dass eine isolierte Nachricht, die einen Versatz von mehr als 100ms vor sich her schiebt, u. U. einzeln verschickt wird. Wenn Dir diese Bedingung genügt, sehe ich keine Notwendigkeit, die Timestamps mitzuschleppen, es sei denn der Empfänger benötigt ihn für irgendwas.

Sorry, aber Du hast den MessageConsumer leider zerstört, indem ausgerechnet, die takes() entfernt hast... ;( : Das ist die zentrale Funktion und gibt der LinkedBlockingQueue ihre Daseinsberechtigung. Der take()-Aufruf hält den Thread solange an, bis mindestens 1 Element in der Queue ist. Falls nach dem Aufwachen noch Zeit ist, wird solange weiter geschlafen, bis die 100ms abgelaufen sind. In dieser Zeit treffen vielleicht noch ein paar Nachrichten ein, die noch erwischt werden. Da muss man keine Timestamps mitschleppen oder berechnen sondern sich nur merken, wann man zuletzt aufgewacht ist. Dann wird nicht-blockierend die Queue noch entleert und abgesendet.

Übrigens hast Du in der start()-Methode die Idee vom MessageProducer heftig "vergewaltigt", indem Du durch die submit()-s immer einen neuen Thread erezugst, der sofort terminiert. Der Code gehört in einen eigenen MessageProducer.
 

Fohnbit

Top Contributor
Hallo Kay!

Jessas! Das .take() wartet bis ein Eintrag in der Queue ist wußte ich nicht. Nun ist mir klar warum nicht auf .isEmpty() geprüft wurde!
Habs aus der JavaDoc nicht heruasgelesen. Das muss also wieder rein :)

Ja, der MessageProducer ist sicher noch nicht korrekt! Aber ich muss die Messages außerhalb generieren, da die Infos von einem anderen System kommen.

Dank dir für deine Hilfe!
 

Fohnbit

Top Contributor
Übrigens hast Du in der start()-Methode die Idee vom MessageProducer heftig "vergewaltigt", indem Du durch die submit()-s immer einen neuen Thread erezugst, der sofort terminiert. Der Code gehört in einen eigenen MessageProducer.

Hier hänge ich nun noch. Du meinst der MessageProducer soll ein Thread sein, der alle Messages in die Queue legt?
Dann muss ich ja einem laufenden Thread die Daten übergeben.
Habs mal versucht, jedoch läuft der Code nun ca. 6x länger als vorher. Es sind auch wesentlich kleinere Queue's als vorher.
Den MessageConsumer habe ich wiederhergestellt.
Hab den Code wieder als Zip angehängt.

Bezüglich des lastTransmission: Hier denk ich immer noch das es nicht optimal ist (oder ich verstehe den Code nicht richtig):
1. MessageConsumer startet
2. in der call() wartet er auf final Message take = queue.take(); bis eine Message in der Queue ist
3. Ein Eintrag kommt in die Queue, der Code im MessageConsumer läuft weiter

und genau hier verstehe ich die lastTransmission nicht. Wenn der Code sowieso auf den ersten Eintrag wartet kann ich ja gleich hinter . take() einen Sleep(100) einbauen.
Dann wartet er immer 100ms nach dem 1. Eintrag bevor er die Queue sendet. Einzig die Verzögerung vom Eintragen der ersten Message in die Queue bis zum .take() ist nicht berücksichtigt.
Oder sehe ich das (wieder) falsch?

Vielen Dank für deine/Eure Hilfe(!)
 

Anhänge

  • Dispatch.zip
    3,9 KB · Aufrufe: 13
Zuletzt bearbeitet:

kay73

Bekanntes Mitglied
Hallo Fohnbit,

Du hast natürlich recht, man kann selbstverständlich pauschal 100ms nach einem take() warten. Und meine Implementierung ist auch noch fehlerhaft. Ich habe das eingebaut, um mit Paketstürmen etwas besser umgehen zu können und dabei prompt zwei Zeilen vertauscht: Eigentlich muss
Code:
lastTransmission
vor dem
Code:
messageListener.onMessages(host, messages);
laufen. Sinn der Sache ist: Wenn das Senden "lange" dauert, ruft das take() die Message "spät" aus der Queue ab und dann soll kürzer gewartet und die Verspätung der ersten Message dadurch etwas kompensiert werden. Ich weiss ja nicht wie zeitkritisch das bei Dir alles ist; vielleicht kannst Du die verkürzte Wartezeitberechnung einfach rausnehmen.

Was die Architektur betrifft: Der MessageProducer ist ein "Pattern" aus dem Consumer-/Producerproblem und wäre im echten Leben die Klasse, die auf dem Netzwerkinterface lauscht, die eingehenden Nachrichten nach Hosts trennt usw. Die also die ganze Arbeit macht und nicht nur die Queues bestückt.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
K Warum wird hier nur etwas in eine txt Datei geschrieben und nicht in alle drei (InputStream/OutputStream/Reader/Writer) Java Basics - Anfänger-Themen 1
H Nutzt Eclipse alle CPU-Threads beim Ausführen von Java-Programmen? Java Basics - Anfänger-Themen 4
B Alle Strings bis zu einer Maimallänge aufzählen, die Bedingung erfüllen Java Basics - Anfänger-Themen 13
D Apache HTTPClient für alle Fälle Java Basics - Anfänger-Themen 41
missy72 Methoden Alle rekusiven Aufrufe abbrechen Java Basics - Anfänger-Themen 21
S IntelliJ geht alle Klassen durch Java Basics - Anfänger-Themen 9
B Alle Zahlen finden, die 3 bestimmte Ziffern enthalten? Java Basics - Anfänger-Themen 9
K wie kann ich alle Attribute von dem Objekt(pagode) ausgeben lassen ? Java Basics - Anfänger-Themen 3
I Greenscreen, funktioniert nicht zu 100%... nicht alle Pixel werden geändert Java Basics - Anfänger-Themen 1
Butzibu Image Loader lädt nicht alle Bilder: Java Basics - Anfänger-Themen 4
sserio Wieso werden nicht alle Primzahlen bis 1000 in meine Liste gepackt ? Java Basics - Anfänger-Themen 8
E Select nimmt nicht alle Where /AND befehlen an Java Basics - Anfänger-Themen 4
K Erste Schritte Wie schnell ist LinkedHashMap im Vergleich zur ArrayList, wenn alle Entries durchlaufen werden? Java Basics - Anfänger-Themen 47
R Methoden Eclipse schlägt mir nicht alle Möglichkeiten vor Java Basics - Anfänger-Themen 4
melisax Alle Möglichkeiten eines Wortes angeben Java Basics - Anfänger-Themen 3
B Programm, dass alle 3 Tage eine Webseite öffnet? Java Basics - Anfänger-Themen 20
J Alle .java Dateien von einem Verzeichnis in eine Zip speichern Java Basics - Anfänger-Themen 2
J Alle Dateien aus einem Verzeichnis laden Java Basics - Anfänger-Themen 10
Bademeister007 Operatoren Alle Zahlen einer ArrayList die durch 5 teilbar ist Java Basics - Anfänger-Themen 2
E Wie gebe ich alle Daten zwischen zwei Zeitpunkten aus? Java Basics - Anfänger-Themen 2
crrnogorka Letzte Zeile einer Tabelle "überschreibt" alle anderen Zeilen Java Basics - Anfänger-Themen 1
C alle möglichen Kombinationen zweier Ziffern auf drei / vier / und 'n" Stellen Java Basics - Anfänger-Themen 11
H Alle Geraden zahlen bis 10 ausgeben Java Basics - Anfänger-Themen 11
L Alle Ziele in einem Raster abknallen Java Basics - Anfänger-Themen 17
J Alle Werte eines Strings zusammen addieren Java Basics - Anfänger-Themen 15
S Laufzeit Quicksort wenn alle Elemente gleich sind Java Basics - Anfänger-Themen 4
B Alle Links in einem Text suchen und ersetzen mit einem neuen Link Java Basics - Anfänger-Themen 18
K Array alle Werte aufsummieren und ausgeben Java Basics - Anfänger-Themen 6
Dimax Erste Schritte String replace alle Zeichen Java Basics - Anfänger-Themen 10
L Wie vergrößere ich ein Rechteck in alle Richtungen um eins und bekomme dessen Rand? Java Basics - Anfänger-Themen 2
L Breadth-First Search statt einem Pfad, alle Pfade herausfinden Java Basics - Anfänger-Themen 4
X Erste Schritte String: Alle doppelten Leerzeilen entfernen Java Basics - Anfänger-Themen 21
M Regex-Ausdruck: Alle Zeichen bis auf ein bestimmtes erlauben (p{L}) Java Basics - Anfänger-Themen 5
I Alle Elemente von zwei Listen vergleichen Java Basics - Anfänger-Themen 1
Kirby.exe Alle möglichen Error Möglichkeiten abfangen Java Basics - Anfänger-Themen 33
M Unterklasse soll nicht alle Methoden erben Java Basics - Anfänger-Themen 3
V Erste Schritte for-Schleife; Ausgabe soll alle 5 Sekunden erfolgen. Java Basics - Anfänger-Themen 4
A Alle true Werte eines boolean Arrays herausfiltern Java Basics - Anfänger-Themen 19
D Alle Möglichkeiten, n-Anzahl aus Elementen aus einem Array zu wählen, ausgeben? Java Basics - Anfänger-Themen 23
M prüfen ob alle array werte gleich sind Java Basics - Anfänger-Themen 27
F Alle Zeichenkombinationen eines Strings iterativ herausfinden Java Basics - Anfänger-Themen 26
L Classpath Alle Dateien im Classpath finden Java Basics - Anfänger-Themen 4
G Überprüfen ob alle Ziffern von 1-9 in einem Integer vorhanden sind Java Basics - Anfänger-Themen 6
J Erste Schritte Alle möglichen ausgaben von 5 Zahlen als Vector Java Basics - Anfänger-Themen 7
R Methoden Entferne alle identische Knoten (Typ String) aus verkettete Liste Java Basics - Anfänger-Themen 8
D Methoden Eigene Methode um alle Ausgaben aufzurufen Java Basics - Anfänger-Themen 17
F Ordner auf alle Unterdatein abfragen Java Basics - Anfänger-Themen 3
A In einem String alle Eigennamen zählen Java Basics - Anfänger-Themen 6
B Klassen Alle Unter-Objekte durchlaufen in der Hauptklasse Java Basics - Anfänger-Themen 10
W ArrayList löscht alle Elemente bis auf eines Java Basics - Anfänger-Themen 2
B Webservice -> alle parameter bekommen von form Java Basics - Anfänger-Themen 2
das_leon Alle Zeilen einer CSV-Datei auslesen Java Basics - Anfänger-Themen 1
C HashMap - alle keys haben values der letzten put-Anweisung Java Basics - Anfänger-Themen 3
F Eclipse alle Projekt weg Java Basics - Anfänger-Themen 6
V Alle Komponenten eines JPanels Java Basics - Anfänger-Themen 14
I gemeinsame Config-Datei für alle Windows-User Java Basics - Anfänger-Themen 5
H JButton - Wechsel der Textfarbe alle 500ms Java Basics - Anfänger-Themen 10
DaCrazyJavaExpert Alle Zahlenkombinationen aus 9 zahlen finden Java Basics - Anfänger-Themen 17
F Alle Objekte einer Klasse nach Eigenschaft durchsuchen Java Basics - Anfänger-Themen 8
M Alle Instanzen einer Klasse ansprechen Java Basics - Anfänger-Themen 4
S Problem: Array alle Einträge gleich Java Basics - Anfänger-Themen 10
Z Enter Taste alle 0,5 Sekunden ausführen Java Basics - Anfänger-Themen 1
U RegEx alle Kommas bei den Zahlen in Punkt umwandeln Java Basics - Anfänger-Themen 3
K alle Vorkommen einer bestimmten Ziffer in einer Zahl zählen Java Basics - Anfänger-Themen 2
X Minimax-Algorithmus über alle Kanten möglich? - Kanten darstellen Java Basics - Anfänger-Themen 1
C Alle Zweierpotenzen bis 2^10 ausgeben lassen Java Basics - Anfänger-Themen 15
B Alle Attribute von Klasse bekommen und ändern Java Basics - Anfänger-Themen 12
M Input/Output Alle Zeilen auslesen und in Variable speichern Java Basics - Anfänger-Themen 5
W Mozilla Thunderbird email an alle Kontakte Java Basics - Anfänger-Themen 3
F Methode alle 15min ausführen Java Basics - Anfänger-Themen 5
D Alle möglichen Kombinationen in einem Array ausgeben Java Basics - Anfänger-Themen 2
I Alle Laufwerke und deres Pfade ausgeben Java Basics - Anfänger-Themen 6
S Classpath: Alle .jars innerhalb eines Ordners einbinden Java Basics - Anfänger-Themen 4
G Alle Objekte und Variablen automatisch ausgeben Java Basics - Anfänger-Themen 7
I Programm, welches eine Textzeile einliest und alle darin enthaltenen Buchstaben umwandelt Java Basics - Anfänger-Themen 3
G Wie bekomme ich alle Ausgaben von runTime.exec() Java Basics - Anfänger-Themen 7
L Best Practice Alle Kombinationen aus Listenelementen, Anzahl Listen unterschiedlich Java Basics - Anfänger-Themen 6
M Compiler-Fehler Alle Methoden eines Interfaces Implementiert dennoch Fehler Java Basics - Anfänger-Themen 3
I Alle Zeitzonen in Liste speichern Java Basics - Anfänger-Themen 4
M Alle Sublisten einer bestimmten Laenge berechnen Java Basics - Anfänger-Themen 2
F Alle DEMOS fast veraltet...? Java Basics - Anfänger-Themen 13
J Alle Leerzeichen aus String entfernen Java Basics - Anfänger-Themen 13
D Methoden Alle Siebenstelligen Primpalidrome von PI Java Basics - Anfänger-Themen 6
K Durch alle Attribute eines Objektes iterieren Java Basics - Anfänger-Themen 6
P Klassen Alle Strings einer ArrayList<eigeneKlasse> anspre Java Basics - Anfänger-Themen 2
W String von hinten alle drei Zeichen abschneiden und in umgekehrter Reihenfolge ausgeben. Java Basics - Anfänger-Themen 9
M Stürzen alle Rekursive Methoden irgendwann ab? Java Basics - Anfänger-Themen 11
M Alle möglichen Strings Java Basics - Anfänger-Themen 5
J Alle Wörter der Länge n mit 0 und 1 Java Basics - Anfänger-Themen 17
T Alle Threads .notify() Java Basics - Anfänger-Themen 13
G Methoden Alle Objekte der ArrayList ausgeben funktioniert nicht. Java Basics - Anfänger-Themen 12
N Klassen Class nur einmal ausführen und sie speichert daten für alle anderen classes? Java Basics - Anfänger-Themen 3
M Klassen Auf Alle Array Methoden gleichzeitig zugreifen Java Basics - Anfänger-Themen 8
D Frame schließt gleich alle Frames Java Basics - Anfänger-Themen 5
T Wie mache ich einen Timer der alle 2 sekunden aufgerufen wird? Java Basics - Anfänger-Themen 5
G JFileChooser "alle Dateien" unterbinden Java Basics - Anfänger-Themen 3
S Aus zwei Dateipfaden alle Dateien auslesen Java Basics - Anfänger-Themen 11
B Frage zur Effizienz - alle Array-Felder initialisieren oder jedes Feld auf null prüfen? Java Basics - Anfänger-Themen 4
F Geht in alle Case rein, warum?? Java Basics - Anfänger-Themen 12
R Alle Klassen ermitteln, die Interface implementieren / Reflection Java Basics - Anfänger-Themen 51

Ähnliche Java Themen

Neue Themen


Oben