удалить Runnable из ScheduledExecutorService

Вот ситуация, код ниже

Пользователь заполняет 3 поля и нажимает кнопку «Добавить» => ToDoBean создается и добавляется в ToDoModel (расширяет AbstractTableModel), а Runnable создается с индексом ToDoBean в модели. Runnable запускается немедленно через ScheduledExecutorService.

Цель Runnable — уменьшать значение int до тех пор, пока оно не достигнет нуля.

Все работает нормально.

Теперь пользователь также может выбрать строку в JTable и нажать кнопку «Удалить», чтобы удалить ToDoBean из списка.

Мой вопрос: когда я удаляю компонент, похоже, что он также удаляется из ScheduledExecutorService. Почему? Как? На самом деле, это именно то, что мне нужно, но я хотел бы понять механизмы. Спасибо

Код:

package demo.todolist;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.WindowConstants;

public class ToDoFrame extends javax.swing.JFrame {

    private final static int POOL_SIZE = 10;
    private ToDoModel model = new ToDoModel();
    private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(POOL_SIZE);           

    /** Creates new form ToDoFrame */
    public ToDoFrame() {
        initComponents();
    }

    private ToDoBean createToDoBean() {
        return new ToDoBean(jTextField1.getText(), jTextField2.getText(), Long.valueOf(jTextField3.getText()));
    }

    private void addToList(ToDoBean toDoBean) {
        model.addToDoBean(toDoBean);
        scheduledExecutorService.schedule(new UpdateRunnable(model.getRowCount() - 1), 0,TimeUnit.SECONDS);
    }

    private class UpdateRunnable implements Runnable {

        private int index;

        public UpdateRunnable(int index) {
            this.index = index;
        }

        @Override
        public void run() {
            System.out.println("Task for index " + index + " started");
            while (model.getToDoBeanAt(index).getDelay() > 0) {
                try {
                    Thread.sleep(10000);
                    model.decreaseBeanAt(index);
                    System.out.println("Delay decreased at index " + index);

                } catch (InterruptedException ex) {
                    Logger.getLogger(ToDoFrame.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            System.out.println("Task for index " + index + " ended");
        }
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void initComponents() {
        GridBagConstraints gridBagConstraints;

        jLabel1 = new JLabel();
        jLabel2 = new JLabel();
        jLabel3 = new JLabel();
        jTextField1 = new JTextField();
        jTextField2 = new JTextField();
        jTextField3 = new JTextField();
        jButton1 = new JButton();
        jScrollPane1 = new JScrollPane();
        jTable1 = new JTable();
        jButton2 = new JButton();

        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        getContentPane().setLayout(new GridBagLayout());

        jLabel1.setText("Name :");
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.anchor = GridBagConstraints.LINE_END;
        gridBagConstraints.insets = new Insets(5, 5, 5, 5);
        getContentPane().add(jLabel1, gridBagConstraints);

        jLabel2.setText("Description :");
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = GridBagConstraints.LINE_END;
        gridBagConstraints.insets = new Insets(5, 5, 5, 5);
        getContentPane().add(jLabel2, gridBagConstraints);

        jLabel3.setText("Delai (seconds) :");
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = GridBagConstraints.LINE_END;
        gridBagConstraints.insets = new Insets(5, 5, 5, 5);
        getContentPane().add(jLabel3, gridBagConstraints);

        jTextField1.setText("my name ");
        jTextField1.setMinimumSize(new Dimension(50, 25));
        jTextField1.setPreferredSize(new Dimension(80, 27));
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.anchor = GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new Insets(5, 5, 5, 5);
        getContentPane().add(jTextField1, gridBagConstraints);

        jTextField2.setText("some description");
        jTextField2.setMinimumSize(new Dimension(145, 25));
        jTextField2.setPreferredSize(new Dimension(145, 27));
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.anchor = GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new Insets(5, 5, 5, 5);
        getContentPane().add(jTextField2, gridBagConstraints);

        jTextField3.setHorizontalAlignment(JTextField.TRAILING);
        jTextField3.setText("5");
        jTextField3.setMinimumSize(new Dimension(25, 25));
        jTextField3.setPreferredSize(new Dimension(25, 27));
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = GridBagConstraints.LINE_START;
        gridBagConstraints.insets = new Insets(5, 5, 5, 5);
        getContentPane().add(jTextField3, gridBagConstraints);

        jButton1.setText("Add");
        jButton1.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });
        getContentPane().add(jButton1, new GridBagConstraints());

        jScrollPane1.setMinimumSize(new Dimension(280, 150));
        jScrollPane1.setPreferredSize(new Dimension(280, 275));

        jTable1.setModel(model
        );
        jScrollPane1.setViewportView(jTable1);

        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.gridwidth = 3;
        getContentPane().add(jScrollPane1, gridBagConstraints);

        jButton2.setText("Remove");
        jButton2.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });
        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 2;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.insets = new Insets(5, 5, 5, 5);
        getContentPane().add(jButton2, gridBagConstraints);

        pack();
    }// </editor-fold>

    private void jButton1ActionPerformed(ActionEvent evt) {
        addToList(createToDoBean());
    }

    private void jButton2ActionPerformed(ActionEvent evt) {
        int rowIndex = jTable1.getSelectedRow();
        model.removeToDoBeanAt(rowIndex); 
        /*
         * the ToDoBean is removed from the list
         * the table is updated
         * the scheduledExecutorService is also updated ... why?
         */
    }

    /**
     * @param args the command line arguments
     */
    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(ToDoFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(ToDoFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(ToDoFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(ToDoFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new ToDoFrame().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify
    private JButton jButton1;
    private JButton jButton2;
    private JLabel jLabel1;
    private JLabel jLabel2;
    private JLabel jLabel3;
    private JScrollPane jScrollPane1;
    private JTable jTable1;
    private JTextField jTextField1;
    private JTextField jTextField2;
    private JTextField jTextField3;
    // End of variables declaration
}

пакет demo.todolist;

импортировать java.util.ArrayList; импортировать java.util.List; импортировать javax.swing.table.AbstractTableModel;

открытый класс ToDoModel расширяет AbstractTableModel {

protected List<ToDoBean> list = new ArrayList<ToDoBean>();
private final static String[] columns = {"Name", "Description", "Remaining"};
private final static Class[] columnsClass = {String.class, String.class, Long.class};
public final static int[] columnWidths = {80, 150, 50}; // 280

public ToDoModel() {
}

public ToDoModel(List<ToDoBean> list) {
    super();
    this.list = list;
}

@Override
public Class getColumnClass(int columnIndex) {
    return columnsClass[columnIndex];
}

@Override
public int getRowCount() {
    return list.size();
}

@Override
public int getColumnCount() {
    return columns.length;
}

@Override
public String getColumnName(int col) {
    return columns[col];
}

@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
    return false;
}

@Override
public Object getValueAt(int rowIndex, int columnIndex) {
    ToDoBean result = list.get(rowIndex);
    switch (columnIndex) {
        case 0:
            return result.getName();
        case 1:
            return result.getDescription();
        default:
            return result.getDelay();
    }
}

@Override
public void setValueAt(Object obj,int rowIndex, int columnIndex) {
    ToDoBean result = list.get(rowIndex);
    switch (columnIndex) {
        case 0:
            result.setName((String) obj);
            break;
        case 1:
            result.setDescription((String) obj);
            break;
        default:
            result.setDelay((Long) obj);
    }
    list.set(rowIndex, result);
    this.fireTableCellUpdated(rowIndex, columnIndex);
}

public void addToDoBean(ToDoBean w) {
    list.add(w);
    fireTableDataChanged();
}

public void addToDoBeanList(List l) {
    list.addAll(l);
    fireTableDataChanged();
}

public ToDoBean getToDoBeanAt(int row) {
    return list.get(row);
}

public ToDoBean removeToDoBeanAt(int row) {
    ToDoBean pos = list.remove(row);
    fireTableDataChanged();
    return pos;
}

public long decreaseBeanAt(int rowIndex) {
    ToDoBean result = list.get(rowIndex);
    long remaining = result.getDelay();
    result.setDelay(--remaining);
    this.fireTableCellUpdated(rowIndex, 2);
    return remaining;
} }

пакет demo.todolist;

открытый класс ToDoBean {

private String name;
private String description;
private long delay;

public ToDoBean(String name, String description, long delay) {
    this.name = name;
    this.description = description;
    this.delay = delay;
}

public ToDoBean() {
}

public long getDelay() {
    return delay;
}

public void setDelay(long delay) {
    this.delay = delay;
}

public String getDescription() {
    return description;
}

public void setDescription(String description) {
    this.description = description;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public void decrease() {
    delay--;
} }

person Hugues    schedule 16.11.2012    source источник
comment
Дополнительные ответы на stackoverflow.com/ вопросы/14423449/   -  person Stefan Birkner    schedule 11.04.2018


Ответы (1)


Я наткнулся на ваш вопрос, и у меня есть хорошее решение. Используйте ScheduledThreadPoolExecutor. Это позволит вам планировать задачи, а также удалять их, когда они больше не нужны.

person Jon    schedule 18.02.2016