Словарь
Поток, процесс, 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.играй_гармонь