Comment mettre en Pause et Reprendre un Thread en Java à partir d'un autre Thread
Je suis en train d'écrire une application avec Java Swing. Ce dont j'ai besoin est une procédure où je peux arrêter de "l'élaboration" fil à l'aide d'un bouton dans l'interface graphique.
Ici un simple projet s'est concentré sur ce que j'ai besoin de
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JTextArea;
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* @author Nikola
*/
public class Main extends javax.swing.JFrame
{
private MyThread THREAD;
public Main()
{
initComponents();
}
@SuppressWarnings("unchecked")
//<editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jButton1 = new javax.swing.JButton();
jScrollPane1 = new javax.swing.JScrollPane();
jTextArea1 = new javax.swing.JTextArea();
jButton2 = new javax.swing.JButton();
jButton3 = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jButton1.setText("Pause Thread");
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
jTextArea1.setColumns(20);
jTextArea1.setRows(5);
jScrollPane1.setViewportView(jTextArea1);
jButton2.setText("Resume Thread");
jButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton2ActionPerformed(evt);
}
});
jButton3.setText("Start Thread");
jButton3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton3ActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(jButton3)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 63, Short.MAX_VALUE)
.addComponent(jButton2)
.addGap(18, 18, 18)
.addComponent(jButton1))
.addComponent(jScrollPane1))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 244, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jButton1)
.addComponent(jButton2)
.addComponent(jButton3))
.addContainerGap())
);
pack();
}//</editor-fold>
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt)
{
THREAD = new MyThread(jTextArea1);
THREAD.start();
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
{
try
{
THREAD.pauseThread();
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt)
{
THREAD.resumeThread();
}
public static void main(String args[])
{
/*
* Set the Nimbus look and feel
*/
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/*
* If Nimbus (introduced in Java SE 6) is not available, stay with the
* default look and feel. For details see
* http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try
{
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels())
{
if ("Nimbus".equals(info.getName()))
{
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
}
catch (ClassNotFoundException ex)
{
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
catch (InstantiationException ex)
{
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
catch (IllegalAccessException ex)
{
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
catch (javax.swing.UnsupportedLookAndFeelException ex)
{
java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/*
* Create and display the form
*/
java.awt.EventQueue.invokeLater(new Runnable()
{
public void run()
{
new Main().setVisible(true);
}
});
}
//Variables declaration - do not modify
private javax.swing.JButton jButton1;
private javax.swing.JButton jButton2;
private javax.swing.JButton jButton3;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTextArea jTextArea1;
//End of variables declaration
}
class MyThread extends Thread
{
JTextArea area;
private final Object lock = new Object();
public MyThread(JTextArea area)
{
super();
this.area = area;
}
@Override
public void run()
{
for(int i=0 ; ; i++)
area.setText(i+"");
}
public void pauseThread() throws InterruptedException
{
synchronized(lock)
{
lock.wait();
}
}
public void resumeThread()
{
synchronized(lock)
{
lock.notify();
}
}
}
La question est simple:
Dans l'application, l'utilisateur de définir certaines options, puis démarrer le thread qui fait de l'élaboration des données sélectionnées.
Je veux fournir un bouton "pause" de sorte que l'utilisateur peut arrêter temporairement l'élaboration et de faire certains besoin de vérifier et après que l'on peut reprendre l'opération.
Dans la façon dont j'ai codé est le graphique thread qui s'arrêtent, pas l ' "élaboration" un.
Si vous exécutez l'exemple de code et appuyez sur "Start" le textarea commence à compter. Le résultat final que j'ai besoin, c'est que lorsque j'appuie sur le bouton "Pause" le fil pour aller "dormir" et le comptage s'arrête, quand je presse la touche "Reprendre" le fil "se réveille" et le comptage dans la zone de texte commence contre les compter.
Vous devez vous connecter pour publier un commentaire.
Vous ne pouvez pas définitivement interrompre un thread d'un autre dans la façon dont vous semblez vouloir.
Ce que vous devez faire à la place, est signal que l'autre thread devrait cesser, par la mise en une sorte de drapeau. Le fil en question doit avoir une logique pour vérifier ce drapeau et la pause de son travail quand cela arrive.
Donc, dans ce cas particulier, peut-être changer d'
MyThread
comme suit:C'est un exemple brut que pour des raisons de concision utilise une sorte de spinlock plutôt que de moniteur approprié à base de couchage. Espérons que celui-ci communique l'idée de la façon dont vous utilisez un indicateur de contrôle de l'arrêt du thread.
Noter que si vous faisiez quelques longue série de mesures à l'intérieur du bloc, au lieu de simplement le
setText
appel, il serait de bonne pratique pour vérifierThread.currentThread().interrupted()
entre chacune des étapes et de sortir de la boucle si le itnerrupt drapeau est réglé. C'est largement ce que l'intégré dans le blocage de méthodes (par exemple, I/O) faire de sorte qu'ils peuvent être interrompus par d'autres threads - depuis lerunning
drapeau est seulement vérifié un par boucle, il n'a pas beaucoup de bien de le définir lors de chaque tour de boucle dure 20 minutes.resumeThread()
ne fonctionnera pas carpauseThread()
va quitter la boucle for.run()
méthode est exécutée jusqu'à la fin. Le fil ne peut pas être mis en pause en tant que tel, surtout pas à l'extérieur; plutôt, vous devez avoir le thread code bloc/attendre à quelque chose à la place. (Dans l'idéal, ce serait par des moniteurs/serrures plutôt que spinlocking, que le premier est plus efficace pour l'ordonnancement des threads au niveau de l'OS, mais le principe est le même.)wait
s ouawait
s le thread qui effectue l'action se suspendre. Donc, si vous arrivé à invoquerpauseThread
de l'event dispatch thread que vous avez probablement vu la totalité de l'écran freeze.pauseThread()
qui peut lever une exception.Essayer comme ça:
C'est une bonne idead d'utiliser des moniteurs comme vous l'avez fait. Mais vous ne pouvez pas forcer l'attente de l'extérieur. Vous devez indiquer le fil d'attendre, jusqu'à ce que vous lui notifier à nouveau (sur le moniteur). Dans ce cas, vous avez juste cette méthode simple
checkForPaused()
que vous devrez mettre dans des positions stratégiques, donc il n'est pas un long délai d'attente jusqu'à ce que le thread est suspendu.Vous pouvez également étendre cette fonction de sorte que vous pouvez demander le thread si il est suspendu avec un indicateur défini dans
checkForPaused()
et unpublic boolean isPausing()
.GUI_INITIALIZATION_MONITOR
dans checkForPaused(), puis de synchroniser surlock
dans resumeThread()? J'aurais également prévu d'utiliser le même moniteur pour les appels à wait() et notify()