I'm writing an application with Java Swing. What i need is a procedure where i can stop the "elaboration" thread using a button in the graphic interface.
Here a simple project focused on what i need
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();
}
}
}
The question is simple: In the real application, the user set some options and then start the thread which doing the elaboration of the selected data.
I want to provide a "pause" button so the user can stop temporarily the elaboration and make some needed check and after that can resume the operation.
In the way i coded is the graphic thread that stop, not the "elaboration" one.
If you run my sample code and press "Start" the textarea starts to counting. The final result that i need is that when i press the "Pause" button the thread go to "sleep" and the counting stops, when i press the "Resume" button the thread "wakes up" and the counting in the text area starts againt to count.
You can't definitively pause one thread from another in the way you seem to want.
What you need to do instead, is signal that the other thread should stop, by setting some sort of flag. The thread in question must have logic to check this flag and pause its work when that happens.
So in this particular case, perhaps change MyThread
as follows:
class MyThread extends Thread {
private volatile boolean running = true; // Run unless told to pause
...
@Override
public void run()
{
for(int i=0 ; ; i++)
{
// Only keep painting while "running" is true
// This is a crude implementation of pausing the thread
while (!running)
yield;
area.setText(i+"");
}
public void pauseThread() throws InterruptedException
{
running = false;
}
public void resumeThread()
{
running = true;
}
}
This is a crude example that for brevity uses a sort of spinlock rather than proper monitor-based sleeping. Hopefully though it communicates the idea of how you use a flag to control the pausing of the thread.
Note that if you were doing some long-running set of steps within the block, instead of just the setText
call, it would be good practice to check Thread.currentThread().interrupted()
between each of the steps - and exit the loop if the itnerrupt flag is set. This is broadly what the built-in blocking methods (e.g. I/O) do so that they can be interrupted by other threads - since the running
flag is only checked one per loop, it doesn't do much good to set it if each loop takes 20 minutes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With