Forum: PC-Programmierung Java Thread Messaging


von J.W. (Gast)


Lesenswert?

Hallo,
ich habe ein Java Programm, wo ich von einem Can-Adapter Daten empfange, 
die ich mit wenigst Zeitverzug auf LAN/Udp weiterreiche.
Das funktioniert sehr gut.

Parallel moechte ich die Daten per System.out.println auf der Konsole 
sehen, und das bremst meine Bridge aus.
Wenn ich das Konsolen-Window verschiebe, dan haengt die Bridge total.

Deshalb mache ich die println-Ausgaben in einem extra Thread
1
static class printOut implements Runnable
2
{
3
ArrayBlockingQueue<byte[]> queue;
4
5
printOut() {
6
  queue=new ArrayBlockingQueue<byte[]>(100,true);
7
}
8
9
public void run()
10
{
11
  byte[] rec=null;
12
  while (true)
13
  {
14
    try {rec=queue.poll(1,TimeUnit.MINUTES);}
15
    catch (InterruptedException exc) {}
16
    if (null==rec)
17
    {
18
      System.out.println("Timeout");
19
      continue;
20
    }
21
    System.out.println ...
22
  }
23
}
24
public void push(byte[] val)
25
{
26
  queue.add(val);
27
}
28
}


Woanders wandle ich die CAN-Daten in ein Byte Array und schiebe dieses 
Array in die obige Queue.

Das Funktioniert zwar, aber es gefaellt mir nicht:
Bei jeder Message wird ein byte[]-Array angelegt.
Irgendwann ist der Speicher voll, und dann bremst der Garbage-Kollektor 
das System.
Ich muss dazu sagen, dass ich bei Java bei zeitkritischen Programmen 
dynamische Speicherbelegungen vermeide, d.h. ich lege die Objekte bei 
Programmstart an und erzeuge dann moeglichst wenig neue.

Wie koennte ich mein Problem anders/besser loesen, d.h. 
System.out.println() Ausgaben, die das System nicht ausbremsen?

Gruss, Juergen

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

J.W. schrieb:
> Parallel moechte ich die Daten per System.out.println auf der Konsole
> sehen, und das bremst meine Bridge aus.
Kann es sein das dein Thread suspended wird in der Zeit?
Du könntest auch mal versuchen das ganze in einen BufferedWriter zu 
wrappen, vieleicht hilft es.

J.W. schrieb:
> Bei jeder Message wird ein byte[]-Array angelegt.
Versteh ich nicht, die Daten müssen doch irgenwo herkommen, also muß das 
byte Array doch so oder so angelegt werden...

Mit Messagin hat das übrigens nix zu tun, du wartest ja nicht auf eine 
Benachrichtigung von einem anderen Thread.

J.W. schrieb:
> Irgendwann ist der Speicher voll, und dann bremst der
> Garbage-Kollektor das System.
Denkst du oder weißt du? Was ist den das für ein System wo alles den 
Bach runtergeht wenn du ne Simple Konsolenausgabe machst und etwas GC...

von J.W. (Gast)


Lesenswert?

Läubi .. schrieb:
> J.W. schrieb:
>> Bei jeder Message wird ein byte[]-Array angelegt.
> Versteh ich nicht, die Daten müssen doch irgenwo herkommen, also muß das
> byte Array doch so oder so angelegt werden...
>

Ohne Extra-Thread legte ich die Daten-Struktur nur einmal an.
Es wurde ja nur eine gebraucht.
1
import peak.can.basic.TPCANMsg;
2
TPCANMsg msg=new TPCANMsg();
3
  while (true)
4
  {
5
    res=pcan.Read(hnd,msg, null);
6
    if (TPCANStatus.PCAN_ERROR_OK==res)
7
    {
8
      //Versenden an Lan
9
      //System.println
10
    }
11
  }

> Mit Messagin hat das übrigens nix zu tun, du wartest ja nicht auf eine
> Benachrichtigung von einem anderen Thread.

Naja, ich dachte, ich muss einem Thread eine Nachricht schicken, dass er 
was ausgibt.
Dabei hatte ich die Windows-Routine PostThreadMessage im Kopf.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Dann übergib die Datenstruktur doch an deine anderen Thread wozu noch 
ein extra Bytearray?

J.W. schrieb:
> Dabei hatte ich die Windows-Routine PostThreadMessage im Kopf.
ThreadMessagin ist eher sowas wie wait und notify, aber egal, tut ja 
hier nix zur Sache.

> if (TPCANStatus.PCAN_ERROR_OK==res)
Schreib es lieber so
> if (res == TPCANStatus.PCAN_ERROR_OK)
Die umgekehrte Schreibweise verwirrt nur.

von J.W. (Gast)


Lesenswert?

Läubi .. schrieb:
> Dann übergib die Datenstruktur doch an deine anderen Thread wozu noch
> ein extra Bytearray?

Geht das?
Arrays und Objekte werden bei java nur als Referenz uebergeben.
Wenn ich in die Queue 20x mal die gleiche Referenz reinschreibe, dann 
holt er immer die aktuellen Werte von diesem Array.
Wobei ich eher annehme, dass das Array in queue.add() kopiert wird und 
neuer Speicher angelegt wird.
Anders waere es, wenn ich int oder long werte in der Queue habe.
Aber ArrayBlockingQueue<E> verlangt Objekte.


>
> J.W. schrieb:
>> Dabei hatte ich die Windows-Routine PostThreadMessage im Kopf.
> ThreadMessagin ist eher sowas wie wait und notify, aber egal, tut ja
> hier nix zur Sache.
>
>> if (TPCANStatus.PCAN_ERROR_OK==res)
> Schreib es lieber so
>> if (res == TPCANStatus.PCAN_ERROR_OK)
> Die umgekehrte Schreibweise verwirrt nur.

Und wenn ich unabsichtlich statt '==' nur '=' schreibe? Das sieht man 
nicht sofort und an solchen Fehlern kann man Stunden/Tage suchen.
Ich spreche aus Erfahrungen.
Irgendwo habe ich gelesen, dass man bei Vergleichen (==) an der linken 
Seite nur Operanden schreibt, die der Compiler nicht als L-Value 
interpretieren kann.
Seitdem habe ich nie mehr = und == verwechselt :-)

von J.W. (Gast)


Lesenswert?

>
> J.W. schrieb:
>> Dabei hatte ich die Windows-Routine PostThreadMessage im Kopf.
> ThreadMessagin ist eher sowas wie wait und notify, aber egal, tut ja
> hier nix zur Sache.
>

Ich denke, das laeuft bei der Queue im Hintergrund ab.
1
  while (true)
2
  {
3
    try {rec=queue.poll(1,TimeUnit.MINUTES);}
4
    catch (InterruptedException exc) {}
Hier bleibt der Thread stehen, bis in der Queue was drinsteht.
D.h. wait und notify
Auch muss die Queue gegenseitig mit Semaphoren gesperrt werden.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

J.W. schrieb:
> Geht das?
Ja warum den nicht?
> Wenn ich in die Queue 20x mal die gleiche Referenz reinschreibe, dann
> holt er immer die aktuellen Werte von diesem Array.
??? Dann hat die Queue halt 20 gleiche Einträge sollte ihn nicht stören 
;)

> Wobei ich eher annehme, dass das Array in queue.add() kopiert wird und
> neuer Speicher angelegt wird.
Diese Annahme würde ich einfach mal ohne Gegenbeweis als nicht 
zutreffend bezeichnen. Wenn du es nicht explizit anforderst wird in Java 
garnix kopiert.

> Anders waere es, wenn ich int oder long werte in der Queue habe.
> Aber ArrayBlockingQueue<E> verlangt Objekte.
ArrayBlockingQueue<Long> nehemen...

> Und wenn ich unabsichtlich statt '==' nur '=' schreibe? Das sieht man
> nicht sofort und an solchen Fehlern kann man Stunden/Tage suchen.
> Ich spreche aus Erfahrungen.
Dann hast du deine Erfahrung aus anderen Sprache, in Java ist
1
int a = 5;
2
if (a = 6) {
3
  //Uppppsss...
4
}
Kein gültiger Code und wird vom Compiler zurückgewiesen: Type mismatch: 
cannot convert from int to boolean.

> Irgendwo habe ich gelesen, dass man bei Vergleichen (==) an der linken
> Seite nur Operanden schreibt, die der Compiler nicht als L-Value
s.o. tut er so auch nicht, es gib in Java nur einen Fall wo das so sein 
kann und das ist bei boolean Werten, diese vergleicht man aber eh nicht 
auf true/false in einer Bedingung.

von J.W. (Gast)


Lesenswert?

> Anders waere es, wenn ich int oder long werte in der Queue habe.
> Aber ArrayBlockingQueue<E> verlangt Objekte.
ArrayBlockingQueue<Long> nehemen...

Mmm, das ist auch wieder ein Objekt, wo der Inhalt dynamisch allokiert 
wird.

>> nicht sofort und an solchen Fehlern kann man Stunden/Tage suchen.
>> Ich spreche aus Erfahrungen.
>Dann hast du deine Erfahrung aus anderen Sprache, in Java ist

Richtig. Die Erfahrung war nicht in Java. Aber man gewoehnt sich 
Schreibweisen an.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

J.W. schrieb:
>> Anders waere es, wenn ich int oder long werte in der Queue habe.
>> Aber ArrayBlockingQueue<E> verlangt Objekte.
> ArrayBlockingQueue<Long> nehemen...
> Mmm, das ist auch wieder ein Objekt, wo der Inhalt dynamisch allokiert
> wird.
Ja nun, irgenwo muß der Speicher für deine Zahl ja her kommen, wo ist 
das Problem? Ich würde da nicht so ängstlich sein, ggf "übersetzt" der 
schlaue Compiler/JVM das sogar in equivalenten Code...

> Richtig. Die Erfahrung war nicht in Java. Aber man gewoehnt sich
> Schreibweisen an.
Für Java würde ich es mir abgewöhnen, es ist einfach unüblich und macht 
den Code schwer lesbar...

von PI314 (Gast)


Lesenswert?

Ich würde das Verschicken vom Ausdrucken einfach entkoppeln...
1
ExecutorService sendService = Executors.newSingleThreadExecutor();
2
ExecutorService printService = Executors.newSingleThreadExecutor();
3
4
while(true){
5
  MyRecord rec = queue.poll();
6
  if(rec != null){
7
    //queue is not empty
8
    sendService.submit(new ElementarSender(rec));
9
    printService.submit(new ElementarPrinter(rec));
10
  } else {
11
    //queue is empty
12
    //sleep...
13
  }
14
}
Will man mehr Kontrolle behalten, steigt man auf peek() um und übergibt 
den Record sammt zwei Future dem dritten Service, der sich nach einer 
bestimmten Strategie ums "Bereinigen" kümmert.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.