Тема: SwingWorker (виконання довгих розрахунків в SWINGу)
Під час створення графічного інтерфейса, часто виникає питання, а що ж робити, коли при натисканні на якусь кнопку виконується "важка" (довга) процедура (підключення до бази даних, читання даних з великого файла, виконання довгих розрахунків, тощо). Пам'ятаю, як дивувався, чому ж не поновлюється JProgressBar, при підключенні до бази даних.   Весь інтерфейс, так би мовити "завмирає" на певний час і навіть кнопка, яку ми натиснули, так і відображається натиснутою. І ось тут, ми стоїмо на роздоріжжі, потрібно застосовувати багатопоточність.
  Весь інтерфейс, так би мовити "завмирає" на певний час і навіть кнопка, яку ми натиснули, так і відображається натиснутою. І ось тут, ми стоїмо на роздоріжжі, потрібно застосовувати багатопоточність.
Є два варіанти: 
1. Реалізувати даний механізм власноруч (напевно, найкращий варіант, проте, значно важчий, аніж 2 варіант). 
2. Використати абстрактний клас SwingWorker (public abstract class SwingWorker<T,V> extends Object implements RunnableFuture<T>).
Що ж то за Worker, такий?
Даний, клас з'явився в 6 версії Java, тобто, ще раз підкреслюю, що розробники, раніше і без нього справлялися.   
 
Проте він був створений, для полегшення вирішення даних задач. Тобто, давайте поглянем на мінімум, який потрібно зробити, для виконання задачі в іншому потоці:
1. Написати клас, який наслідується від класа SwingWorker.
2. Не забуваєм, що SwingWorker абстрактний клас, тому потрібно реалізувати абстрактний метод doInBackground() (protected abstract T doInBackground() throws Exception).
3. Створити об'єкт нашого класу та викликати метод execute() (public final void execute()).
Тобто, як бачимо, нічого надзвичайного не має. А тепер, давайте більш детально пройдемось, по даному класу.
SwingWorker<T,V>
Що таке T та V?
T - тип результату, що повертається методом doInBackground() (можна сказати кінцевий результат).
V - тип проміжкових результатів (відправляється методом publish(V... chunks) (protected final void publish(V... chunks)) з методу doInBackground(), ці результати потрапляють (передаються) до методу process(List<V> chunks) (protected void process(List<V> chunks))).
Самий, цікавий, для нас метод - doInBackground(). Ось тут і потрібно виконувати, нашу "важку" роботу (фонову задачу). Оскільки даний метод буде запущено в окремому потоці. Також треба наголосити, на те, що з елементами GUI працювати в даному методі НЕ РЕКОМЕНДУЄТЬСЯ, проте є деякі виключення. Методи - thread safe (потокозахищені) - JTextComponent.setText(), JTextComponent.print(), JTextArea.insert(), JTextArea.append(), JTextPane.insertIcon(),... (див. офіційну документацію).
Не обов'язково, але при бажанні, з даного метода можемо передавати проміжкові результати методом publish(V... chunks).
Перевизначення методу process(List<V> chunks) використовується, для обробки (показу) проміжних результатів. Ось в цьому методі вже можна працювати, з елементами GUI, оскільки даний метод викликається з Event Dispatch Thread ("рідного" для SWINGа - потоку надсилання подій).
Метод done() (protected void done()) викликається після завершення виконання методу doInBackground(). Тобто, "довга" робота скінчена, ми знову повертаємося в Event Dispatch Thread. І якщо, ми щось хочемо змінити в інтерфейсі, після "довгої" роботи слід перевизначити метод done().
Ну і звичайно, не слід забувати про метод execute(). Який і запускає виконнаня в окремому робочому потоці.
Також, потрібно підкреслити, що об'єкт даного класу, скажімо так, для одноразового використання. Ще один нюанс, даного класу: максимальна кількість потоків - 10. Це означає, що за допомогою класу SwingWorker паралельно можуть виконуватися тільки 10 фонових задач. Якщо потоків створено більше, SwingWorker, ставить нові потоки в чергу очікування.
Тобто, нічого, складного в класі SwingWorker немає. А головне, що даний клас сам потурбується про переключення потоків.
Ось простенький, код, де можна побачити, як застосовувати SwingWorker:
import java.util.List;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class Example extends JFrame {
    private JLabel label = new JLabel();
    public Example() {
        setTitle("Тест SwingWorker");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        JButton button = new JButton("Виконання");
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                new MyWork().execute();
            }
        });
        setLayout(new FlowLayout());
        add(button);
        add(label);
        setSize(300, 300);
        setLocationRelativeTo(null);
        setVisible(true);
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Example();
            }
        });
    }
    class MyWork extends SwingWorker<Void, String> {
        // даний метод запускається в окремому потоці, не в Event Dispatch
        // Thread, тут виконується фонова задача
        @Override
        protected Void doInBackground() throws Exception {
            int i = 0;
            // надсилання проміжкових результатів
            publish("Підраховуємо i");
            while (i < Integer.MAX_VALUE) {
                i++;
            }
            // надсилання проміжкових результатів
            publish("i=" + i);
            Thread.sleep(1000);
            // надсилання проміжкових результатів
            publish("Заснули");
            Thread.sleep(5000);
            // надсилання проміжкових результатів
            publish("Прокинулися");
            Thread.sleep(1000);
            return null;
        }
        // ось цей метод запускається в Event Dispatch Thread, для обробки
        // проміжкових результатів
        @Override
        protected void process(List<String> chunks) {
            for (String x : chunks) {
                label.setText(x);
            }
        }
        // даний метод запускається в Event Dispatch Thread, після виконання
        // методу doInBackground()
        @Override
        protected void done() {
            label.setText("");
        }
    }
}P.S. Ну і звичайно, давайте, не забувати користуватися офіційною документацією Class SwingWorker<T,V>
P.P.S. Звичайно, дана стаття призначена, для початківців, якщо в когось є якісь доповнення, буду радий їх почитати.
