Java a dvě vlákna

jmmm

Java a dvě vlákna
« kdy: 24. 12. 2011, 10:42:29 »
Jak na to, když mám dvě vlákna?

Mám nějaký JPanel a potom nějakou TridaX.
Ve TridaX, je nějaký náročnější výpočet, který je potřeba dát do threadu. V této třídě mám nějaký parametr: double progress, ve kterém si zaznamenávám stav výpočtu (kolik % je již hotovo).
A na JPanelu by se měl vypisovat stav výpočtu v %. Takže jsem tam chtěl udělat další vlákno, které se bude dotazovat té třídy TridaX před její instanci a brat si hodnotu progress a pravidelně vypisovat hodnotu dokud nebude rovna 100%.

Ale nějak se mi nedaří ty vlákna vytvořit, aby to pracovalo správně. Nejspíše ty vlákna definuji nějak špatně. Poradil by mi tu někdo, jak to ty dvě vlákna udělat?


« Poslední změna: 27. 12. 2011, 20:36:13 od Petr Krčmář »


KapitánRUM

Re:java: dve vlakna?
« Odpověď #1 kdy: 24. 12. 2011, 11:31:53 »
Vlákna jsou v Java dost jednoduchá záležitost.

1. nadefinuješ vlákno, viz Google.
2. vlákno si spočítá, jak dlouho mu to bude trvat a přírůstek si počítá samo (vlákno ví nejlépe, jestli je na začátku práce nebo v polovině)
3. pro výměnu dat můžeš použít zápis třeba někam do proměnné třídy
4. hlavní program si animuje průběh

U Threadpoolu, když ti na jedné úloze dělá třeba 10 vláken, to už je složitější.

apoc9

Re:java: dve vlakna?
« Odpověď #2 kdy: 24. 12. 2011, 12:07:38 »
Ve swingu to není tak jednoduché, protože ten je single-thread (není thread safe). Je několik možností buď pomocí
Kód: [Vybrat]
SwingUtilities.invokeLater(Runnable doRun);nebo implementovat
Kód: [Vybrat]
SwingWorker<T,V> To je třída přesně určená pro tyto případy.
Pokud není angličtina pro tebe problém přečti si tento článek http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html

Robert Novotny

Re:java: dve vlakna?
« Odpověď #3 kdy: 24. 12. 2011, 13:28:00 »
invokeLater zrejme nebude potrebny. Ta uloha vyzera presne na pouzitie SwingWorkera, ktory to vsetko zvladne. Za normalnych okolnosti by to bol pomerne nevesely problem spojeny s koordinaciou vlakien.

Svojho casu som napisal clanok k pouzitiu SwingWorkera http://ics.upjs.sk/~novotnyr/wiki/Java/SwingThreads

gazda

Re:java: dve vlakna?
« Odpověď #4 kdy: 25. 12. 2011, 11:40:35 »
Áno, SwingWorker je štandardným riešením vášho problému. Upozorňujem, že SwingWorkerov bolo v minulosti v obehu viacero. Pokiaľ môžete, použite javax.swing.SwingWorker<T, V> z JRE (since 1.6). Ten ponúka API aj pre progress výpočtu.

V Swingu je dôležité manipulovať s GUI výhradne vo vlákne, ktoré sa zvykne označovať ako "event dispatch thread". To sa týka aj vytvorenia a zobrazenia vášho JPanelu a JFramu/JDialogu. Na to je dobrá tá metóda invokeLater.

Tento kód by vám mohol pomôcť:
Kód: [Vybrat]
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import javax.swing.SwingWorker;

import com.h311.swing.GridBagLayout;

public class Test {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {

@Override
public void run() {

final JTextField myResultField = new JTextField();
final JProgressBar myProgress = new JProgressBar();
myProgress.setStringPainted(true);
final JButton myStartButton = new JButton("Start");
myStartButton.setActionCommand("start");
final JButton myCancelButton = new JButton("Cancel");
myCancelButton.setActionCommand("cancel");
myCancelButton.setEnabled(false);
ActionListener actionListener = new ActionListener() {
private SwingWorker<Integer, Integer> worker;
@Override
public void actionPerformed(ActionEvent e) {
if (worker != null) {
worker.cancel(true);
}
if ("start".equals(e.getActionCommand())) {
worker = new SwingWorker<Integer, Integer>(){

@Override
protected Integer doInBackground() throws Exception {

/* 5 seconds */
int durationInMilliseconds = 1000 * 5;

long startTime = System.currentTimeMillis();
long deadLine = startTime  + durationInMilliseconds;

int result = 0;

while (!isCancelled()) {
/* do something meaningful */
long now = System.currentTimeMillis();
if (now > deadLine) {
break;
}
long timeLeft = now - startTime;
publish(Integer.valueOf((int) ((timeLeft / (double)durationInMilliseconds) * 100)));
result++;
}
return result;
}

@Override
protected void process(List<Integer> chunks) {
if (!isCancelled() && chunks != null && chunks.size() > 1) {
/* consider only the last value */
int value = chunks.get(chunks.size() -1);
myProgress.setValue(value);
myProgress.setString(new StringBuilder(3 + 2).append(value).append(' ').append('%').toString());
}
}

@Override
protected void done() {
try {
Integer result = get();
myResultField.setText(String.valueOf(result));
} catch (CancellationException e) {
myProgress.setString("Cancelled");
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
finally {
myStartButton.setEnabled(true);
myCancelButton.setEnabled(false);
}
}

};
myStartButton.setEnabled(false);
myCancelButton.setEnabled(true);
myResultField.setText("");
worker.execute();

}
}

};
myStartButton.addActionListener(actionListener);
myCancelButton.addActionListener(actionListener);

JPanel myPanel = new JPanel(new GridBagLayout());
int row = 0;
GridBagConstraints startConstraints = new GridBagConstraints();
startConstraints.gridx = 0;
startConstraints.gridy = row;
myPanel.add(myStartButton, startConstraints);

GridBagConstraints cancelConstraints = new GridBagConstraints();
cancelConstraints.gridx = 1;
cancelConstraints.gridy = row;
myPanel.add(myCancelButton, cancelConstraints);
row++;

GridBagConstraints progressConstraints = new GridBagConstraints();
progressConstraints.gridx = 0;
progressConstraints.gridy = row;
progressConstraints.fill = GridBagConstraints.HORIZONTAL;
progressConstraints.gridwidth = 2;
myPanel.add(myProgress, progressConstraints);
row++;

GridBagConstraints resultLabelConstraints = new GridBagConstraints();
resultLabelConstraints.gridx = 0;
resultLabelConstraints.gridy = row;
myPanel.add(new JLabel("Iterations"), resultLabelConstraints);
GridBagConstraints resultConstraints = new GridBagConstraints();
resultConstraints.gridx = 1;
resultConstraints.gridy = row;
resultConstraints.fill = GridBagConstraints.HORIZONTAL;
myPanel.add(myResultField, resultConstraints);


JFrame myFrame = new JFrame();
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setContentPane(myPanel);
myFrame.pack();
myFrame.setVisible(true);

}
});
}
}