среда, 1 августа 2012 г.

threads: Thread/Runnable



    Словарь
    Поток, процесс, deadlock, join, OS scheduler, кооперативная многозадачность, вытесняющая многозадачность.


    Материал

    Программа печатает букву "A" каждые 250-500 мс (примерно). Задержка сделана при помощи выполнения дурной работы

public class ThreadExample_0AA {
    public static void main(String[] args) {
        for (int k = 0; k < 10; k++) {
            for (int i = 0; i < 1000000000L; i++) {}
            System.out.println("A");
        }
    }
}

    Программа печатает букву "A" каждые 250 мс. Задержка сделана при помощи статического метода Thread.sleep(long). Обратите внимание - sleep в сигнатуре объявил возможность генерации InterruptedException

public class ThreadExample_0A {
    public static void main(String[] args) throws InterruptedException {
        for (int k = 0; k < 10; k++) {
            Thread.sleep(250);
            System.out.println("A");
        }
    }
}

    Неудачная попытка писать в консоль "A" и " B" одновременно
public class ThreadExample_0B {
    public static void main(String[] args) throws InterruptedException {
        for (int k = 0; k < 10; k++) {
            Thread.sleep(240);
            System.out.println("A");
            f();
        }
    }

    public static void f() throws InterruptedException {
        Thread.sleep(260);
        System.out.println(" B");
    }
}

    Вспомогательный класс (Runnable - шаблон Command)
public class PrintRunnable implements Runnable {
    private String msg;
    private long sleepMillis;

    public PrintRunnable(String msg, long sleepMillis) {
        this.msg = msg;
        this.sleepMillis = sleepMillis;
    }

    @Override
    public void run() {
        for (int k = 0; k < 10; k++) {
            try {
                Thread.sleep(sleepMillis);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(msg);
        }
    }
}
    Интерфейс java.lang.Runnable
package java.lang;

public interface Runnable {
    public void run();
}

    Второй цикл вынесли в класс-команду, но одновременности все нет
public class ThreadExample_0C {
    public static void main(String[] args) throws InterruptedException {
        for (int k = 0; k < 10; k++) {
            Thread.sleep(240);
            System.out.println("A");
        }
        new PrintRunnable(" B", 260).run();
    }
}
    Все еще не одновременно
public class ThreadExample_0D {
    public static void main(String[] args) throws InterruptedException {
        new PrintRunnable(" B", 260).run();
        for (int k = 0; k < 10; k++) {
            Thread.sleep(240);
            System.out.println("A");
        }
    }
}

    Одновременно! Спасибо магии класса java.lang.Thread и методу start().
public class ThreadExample_1A {
    public static void main(String[] args) throws InterruptedException {
        Runnable printer = new PrintRunnable(" B", 1000);
        Thread thread = new Thread(printer);
        thread.start();
        
        for (int k = 0; k < 10; k++) {
            Thread.sleep(250);
            System.out.println("A");
        }
    }
}

    Магия потоков-демонов
public class ThreadExample_1AA {
    public static void main(String[] args) throws InterruptedException {
        Runnable printer = new PrintRunnable(" B", 1000);
        Thread thread = new Thread(printer);
        thread.setDaemon(true);
        thread.start();
        
        for (int k = 0; k < 10; k++) {
            Thread.sleep(250);
            System.out.println("A");
        }
    }
}
    Факт: программа завершает свою работу в момент завершения работы всех потоков не-демонов. Поток, вызвавший main(...), - не демон.

    Кто не стартует, тот никуда не едет
public class ThreadExample_1B {
    public static void main(String[] args) throws InterruptedException {
        Runnable printer = new PrintRunnable(" B", 1000);
        Thread thread = new Thread(printer);
//        thread.start();
        
        for (int k = 0; k < 10; k++) {
            Thread.sleep(250);
            System.out.println("A");
        }
    }
}

    Неудачный план
public class ThreadExample_1C {
    public static void main(String[] args) throws InterruptedException {
        for (int k = 0; k < 10; k++) {
            Thread.sleep(250);
            System.out.println("A");
        }

        Runnable printer = new PrintRunnable(" B", 100);
        Thread thread = new Thread(printer);
        thread.start();
    }
}

    Магия метода Thread.join()
public class ThreadExample_2A {
    public static void main(String[] args) throws InterruptedException {
        Runnable printer = new PrintRunnable(" B", 100);
        Thread thread = new Thread(printer);
        thread.start();

        thread.join();

        for (int k = 0; k < 10; k++) {
            Thread.sleep(250);
            System.out.println("A");
        }
    }
}

public class ThreadExample_2B {
    public static void main(String[] args) throws InterruptedException {
        Runnable printer = new PrintRunnable(" B", 1000);
        Thread thread = new Thread(printer);
        thread.start();

        for (int k = 0; k < 10; k++) {
            Thread.sleep(250);
            System.out.println("A");
        }

        System.out.println("Start wait");
        thread.join();
        System.out.println("Buy-buy!");
    }
}
    Взаимная блокировка (deadlock) в две строки (плюс магия метода Thread.currentThread()) - поток ждет завершение самого себя
public class ThreadExample_3A {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = Thread.currentThread();
        thread.join();
    }
}
    Ну или в одну строку
public class ThreadExample_3AA {
    public static void main(String[] args) throws InterruptedException {
        Thread.currentThread().join();
    }
}
    "Классическая" взаимная блокировка (deadlock) - каждый из двух потоков ждет завершения другого
public class ThreadExample_3B {
    public static void main(String[] args) throws InterruptedException {
        final Thread mainThread = Thread.currentThread();
        Thread runThread = new Thread(new Runnable() {
            public void run() {
                try {
                    System.out.println("Run: wait for main!");
                    mainThread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        runThread.start();

        System.out.println("Main: wait for run!");
        runThread.join();
    }
}

    Можем последовательно запустить два потока, ждать придется тоже последовательно
public class ThreadExample_4A {
    public static void main(String[] args) throws InterruptedException {
        // A
        Runnable printerA = new PrintRunnable("A", 300);
        Thread threadA = new Thread(printerA);
        threadA.start();
        // B
        Runnable printerB = new PrintRunnable(" B", 500);
        Thread threadB = new Thread(printerB);
        threadB.start();

        threadA.join();
        System.out.println("---");
        threadB.join();
        System.out.println("Buy!");
    }
}


    Лабораторные
    1) thread.thread.играй_гармонь
    2) thread.thread.rabbit_attack


    Сами лабораторные можно увидеть тут.