《Java 编程思想》在并发一章中提到了Sleep休眠、优先级、后台线程,提醒读者需要了解但又不能太依赖他们。就让我们一起看看吧。
休眠Sleep
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class App { public static void main(String[] args) { ExecutorService exec=Executors.newFixedThreadPool(10); for(int i=0;i<10;i++){ exec.execute(new Task()); } exec.shutdown(); } } /** * 定义任务 * @author Administrator */ class Task implements Runnable{ @Override public void run() { try { TimeUnit.SECONDS.sleep(2); System.out.println(Thread.currentThread().getId()); } catch (InterruptedException e) { e.printStackTrace(); } } }
这里需要注意:
TimeUnit.SECONDS.sleep(2);
这是Java5后的新方式,以前你可能这样用:
Thread.sleep(2*1000);
不能依赖:不能依赖Sleep来顺序执行任务,如果你需要顺序执行则使用同步机制。
优先级
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; public class App { public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); exec.execute(new Task(Thread.MIN_PRIORITY)); exec.execute(new Task(Thread.MAX_PRIORITY)); exec.shutdown(); } } /** * 定义任务 * * @author Administrator */ class Task implements Runnable { private int priority; public Task(int priority) { this.priority = priority; } @Override public void run() { for (int j = 0; j < 5; j++) { Thread.currentThread().setPriority(priority); for (int i = 0; i < 100; i++) { if (i % 2 == 0) { Thread.yield(); } } System.out.println(Thread.currentThread()); } } }
线程的优先级将该线程的重要性传递给了调度器,尽管CPU处理现有线程的顺序是不确定的,但调度器倾向于让优先权高的线程先执行,而优先权低的线程执行频率较低。
不能依赖:所有的程序都应该以默认的优先级运行,试图操纵线程优先级通常是一种错误,因为没法保证。另:尽管JDK有10个优先级,但多数操作系统都不能很好的映射,比如Windows有7个优先级且不固定,映射关系也不确定,Solaris有231个优先级,所以你最好使用可移植的三个级别:MIN_PRIORITY、NORM_PRIORITY和MAX_PRIORITY。
后台线程
所谓后台(daemon)线程,是指在程序运行的时候在后台提供一种通用服务的线程,并且这种线程并不属于程序中不可或缺的部分。因此,当所有的非后台线程结束时,程序也就终止了,同时会杀死进程中的所有后台线程。而且后台线程有继承性:后台线程产生的线程都是后台线程。
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; public class App { public static void main(String[] args) throws InterruptedException { ExecutorService exec = Executors.newCachedThreadPool(new MyThreadFactory()); exec.execute(new Task()); exec.shutdown(); TimeUnit.MILLISECONDS.sleep(100); } } /** * 定义任务 * * @author Administrator */ class Task implements Runnable { @Override public void run() { for(int i=0;i<100;i++){ try { TimeUnit.MILLISECONDS.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(i); } } } /** * 线程工厂 * @author Administrator * */ class MyThreadFactory implements ThreadFactory{ @Override public Thread newThread(Runnable r) { Thread t=new Thread(r); t.setDaemon(true); return t; } }
示例中使用“ThreadFactory”来设置线程属性的,可以看到输出是打印不完100个就结束了,如果你把Deamon设置为false,就能打印全部。
不能依赖:所有非后台线程一旦结束,后台线程就会立刻终止,这不能以一种优雅的方式关闭线程,所以可能会得到意想不到的结果。
PS:以上三种不能说完全摒弃不用,既然设计了就可能有用的,只是要注意使用弊端,从而达到合理使用。