Эккель Брюс
Шрифт:
*///:-
Чтобы назначить поток демоном, следует перед его запуском вызвать метод setDaemon.
После того как main завершит свою работу, ничто не препятствует завершению программы, поскольку в процессе не работают другие потоки, кроме демонов. Чтобы результаты запуска всех потоков-демонов были более наглядными, поток main на некоторое время погружается в «сон». Без этого вы увидели бы только часть результатов при создании демонов. (Поэкспериментируйте с вызовом sleep для интервалов разной продолжительности.)
В примере SimpleDaemons.java используется явное создание объектов Thread для установки их «демонского» флага. Вы также можете настроить атрибуты (демон, приоритет, имя) потоков, созданных исполнителем; для этого следует написать пользовательскую реализацию ThreadFactory:
//: net/mi ndvi ew/uti1/DaemonThreadFactory.java package net.mindview.util;
import java util.concurrent.*;
public class DaemonThreadFactory implements ThreadFactory { public Thread newThread(Runnable r) { Thread t = new Thread(r), t.setDaemon(true); return t,
}
} /// -
Единственное отличие от обычной реализации 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 демоны запущены"); TimeUnit MILLISECONDS.sleep(500); // Задержка
}
} /// ~
Каждый статический метод создания 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 + ". "); // Даем потокам-демонам завершить процесс запуска: TimeUnit.SECONDS.sleep(l);
}
} /* Output: