Философия Java3
Шрифт:
}
} /// -
Единственное отличие от обычной реализации ThreadFactory заключается в том, что в данном случае атрибут демона задается равным true. Теперь новый объект DaemonThreadFactory передается в аргументе Executors.newCachedThread-Pool:
//: concurrency/DaemonFromFactory java
// Использование ThreadFactory для создания демонов.
import java.util.concurrent.*;
import net mindview util *;
import static net.mindview.util.Print.*,
public class DaemonFromFactory implements Runnable { public void run { try {
while(true) {
TimeUnit MILLISECONDS.sleep(lOO); print(Thread.currentThread + " " + this);
}
} catch(InterruptedException e) { print("Interrupted");
}
}
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors newCachedThreadPool(
new DaemonThreadFactory), for(int i = 0; i < 10. i++)
exec.execute(new DaemonFromFactory); printC'Bce
}
} /// ~
Каждый статический метод создания ExecutorService перегружается для получения объекта ThreadFactory, который будет использоваться для создания новых потоков.
Сделаем еще один шаг — создадим вспомогательный класс DaemonThread-PoolExecutor:
// net/mi ndvi ew/uti1/DaemonThreadPoolExecutor.java package net mindview.util; import java util.concurrent *;
public class DaemonThreadPoolExecutor extends ThreadPoolExecutor {
public DaemonThreadPoolExecutorО {
super(0, Integer MAX_VALUE. 60L. TimeUnit SECONDS.
new SynchronousQueue<Runnable>. продолжение &
new DaemonThreadFactoryO).
}
} /// ~
Чтобы узнать, какие значения должны передаваться при вызове конструктора базового класса, я просто заглянул в исходный код Executors.java.
Чтобы узнать, является ли поток демоном, вызовите метод isDaemon. Если поток является демоном, то все потоки, которые он производит, также будут демонами, что и демонстрируется следующим примером:
//: concurrency/Daemons.java
// Потоки, порождаемые демонами, также являются демонами
import java util.concurrent.*,
import static net mindview util Print.*,
class Daemon implements Runnable {
private Thread[] t = new Thread[10]; public void run {
for(int i = 0; i < t length; i++) {
t[i] = new Thread (new DaemonSpawnO); t[i].startO:
printnb("DaemonSpawn " + i + " started. ");
}
for(int i = 0. i < t.length, i++)
printnb("t[" + i + "]. isDaemonO = " + t[i] isDaemonO + ");
while(true)
Thread.yieldO;
class DaemonSpawn implements Runnable { public void run { while(true)
Thread.yieldO;
public class Daemons {
public static void main(String[] args) throws Exception { Thread d = new Thread(new DaemonO); d.setDaemon(true); d.startO;
printnbC'd.isDaemonO = " + d.isDaemonO + ". "); // Даем
}
} /* Output:
d.isDaemonO = true, DaemonSpawn 0 started, DaemonSpawn 1 started. DaemonSpawn 2 started. DaemonSpawn 3 started. DaemonSpawn 4 started. DaemonSpawn 5 started. DaemonSpawn 6 started, DaemonSpawn 7 started, DaemonSpawn 8 started. DaemonSpawn 9 started. t[0].isDaemonO = true. t[l] isDaemonO = true, t[2].isDaemonO = true, t[3].isDaemonO = true. t[4].isDaemonO = true. t[5].isDaemonO = true. t[6].isDaemonO = true. t[7].isDaemonO = true. t[8].isDaemonO = true. t[9].isDaemonO = true. *///:-
Поток Daemon переводится в режим демона, а затем порождает группу новых потоков, которые явно не назначаются демонами, но при этом все равно оказываются ими. Затем Daemon входит в бесконечный цикл, на каждом шаге которого вызывается метод yield, передающий управление другими процессам.
Учтите, что потоки-демоны завершают свои методы run без выполнения секций finally:
//: concurrency/DaemonsDontRunFinally.java
// Потоки-демоны не выполняют секцию finally.
import java.util.concurrent.*.
import static net.mindview.util.Print.*,
class ADaemon implements Runnable { public void run { try {
print("Запускаем ADaemon"); TimeUnit.SECONDS.sieep(l). } catch(InterruptedException e) {
print("Выход через InterruptedException"); } finally {
print("Должно выполняться всегда?");
}
}
}
public class DaemonsDontRunFinally {
public static void main(String[] args) throws Exception { Thread t = new Thread(new ADaemonO); t.setDaemon(true). t.startO,
}
} /* Output;
Запускаем ADaemon
*///:-
Запуск программы наглядно показывает, что секция finally не выполняется. С другой стороны, если закомментировать вызов setDaemon, вы увидите, что секция finally была выполнена.
Такое поведение верно, даже если из предыдущих описаний finally у вас сложилось обратное впечатление. Демоны завершаются «внезапно», при завершении последнего не-демона. Таким образом, сразу же при выходе из main JVM немедленно прерывает работу всех демонов, не соблюдая никакие формальности. Невозможность корректного завершения демонов ограничивает возможности их применения. Обычно объекты Executor оказываются более удачным решением, потому что все задачи, находящиеся под управлением Executor, могут быть завершены одновременно.
Варианты кодирования
Во всех предшествующих примерах все классы задач реализовали интерфейс Runnable. В очень простых случаях можно использовать альтернативное решение с прямым наследованием от Thread:
//• concurrency/SimpleThread.java // Прямое наследование от класса Thread.
public class SimpleThread extends Thread { private int countDown = 5; private static int threadCount = 0. public SimpleThreadO {
// Сохранение имени потока
super(Integer.toStri ng(++threadCount)).