Sleeping
调用sleep()是一种简单的影响你的任务执行的方式,能让你的任务停止执行一会儿。
例子:
public class SleepingTask extends LiftOff {
@Override
public void run() {
try {
while (countDown-- > 0) {
System.out.println(status());
TimeUnit.MILLISECONDS.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
调用sleep()可能会抛出一个interruptedException,可以在run()方法中被捕获。这个异常不能被传播回主线程。(run方法也没有办法抛出,因为方法的签名上没有抛异常)
Priority
线程的优先级给调度器传递了这个线程的重要性。尽管CPU调度一组线程的顺序是不确定的,但是调度器还是倾向于调度那些优先级比较高的在等待中的线程(很随机,没有用)。
例子:
public class SimplePriority implements Runnable {
private int countDown = 5;
private volatile double d;
private int priority;
public SimplePriority(int priority) {
this.priority = priority;
}
@Override
public String toString() {
return Thread.currentThread() + ":" + countDown;
}
@Override
public void run() {
Thread.currentThread().setPriority(priority);
while (true) {
for (int i = 0; i < 100000; i++) {
d += (Math.PI + Math.E) / (double) i;
if (i % 1000 == 0) {
Thread.yield();
}
}
System.out.println(this);
if (--countDown == 0) {
return;
}
}
}
}
public class MoreBasicThreads {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
executorService.execute(new SimplePriority(Thread.MIN_PRIORITY));
}
executorService.execute(new SimplePriority(Thread.MAX_PRIORITY));
executorService.shutdown();
}
}
Thread[pool-1-thread-6,10,main]:5
Thread[pool-1-thread-2,1,main]:5
Thread[pool-1-thread-4,1,main]:5
Thread[pool-1-thread-1,1,main]:5
Thread[pool-1-thread-5,1,main]:5
Thread[pool-1-thread-6,10,main]:4
Thread[pool-1-thread-3,1,main]:5
Thread[pool-1-thread-1,1,main]:4
Thread[pool-1-thread-4,1,main]:4
Thread[pool-1-thread-6,10,main]:3
Thread[pool-1-thread-2,1,main]:4
Thread[pool-1-thread-5,1,main]:4
Thread[pool-1-thread-6,10,main]:2
有效果,但是不是特别明显,因为其他的低优先级的线程先结束了。
在run方法里面,100,000个重复的浮点数计算,包括了双精度的加和除。volatile保证了没有编译器的优化?(不是很明白)如果注释掉forloop,那么优先级的效果就大打折扣了。(主要是还是如果没有复杂的运算,那么处理器不会倾向于调度别的任务,可以用yield或者sleep达到同样的效果)。
Yielding
使用yield可以告诉调度器这个任务已经完成的差不多了,可以给另外的任务一些调度的机会。但是这个不是强制的,不保证一定会切换。在LiftOff那个例子中,如果使用yield的话,每一个任务完成的时候大概率是在最后。如果去掉了yield,则会出现某一个任务提前做完的情况(调度器不倾向于切换)。
@Override public void run() { while (countDown-- > 0) { System.out.println(status()); Thread.yield(); } } #0(9), #1(9), #2(9), #3(9), #4(9), #1(8), #0(8), #2(8), #3(8), #4(8), #1(7), #0(7), #2(7), #3(7), #4(7), #1(6), #0(6), #2(6), #3(6), #4(6), #1(5), #0(5), #2(5), #3(5), #4(5), #1(4), #0(4), #2(4), #3(4), #4(4), #1(3), #0(3), #2(3), #3(3), #4(3), #1(2), #0(2), #4(2), #3(2), #2(2), #1(1), #0(1), #4(1), #3(1), #2(1), #1(LiftOff!), #0(LiftOff!), #4(LiftOff!), #3(LiftOff!), #2(LiftOff!), @Override public void run() { while (countDown-- > 0) { System.out.println(status()); //Thread.yield(); 去掉yield以后 } } #0(9), #1(9), #1(8), #1(7), #1(6), #1(5), #1(4), #1(3), #1(2), #1(1), #1(LiftOff!), #2(9), #2(8), #2(7), #2(6), #2(5), #2(4), #2(3), #2(2), #2(1), #2(LiftOff!), #0(8), #0(7), #0(6), #0(5), #0(4), #0(3), #0(2), #0(1), #0(LiftOff!), #3(9), #3(8), #3(7), #3(6), #3(5), #3(4), #4(9), #4(8), #4(7), #4(6), #4(5), #4(4), #4(3), #4(2), #4(1), #4(LiftOff!), #3(3), #3(2), #3(1), #3(LiftOff!),
不能依靠yield来控制任务的完成次序!!!
Daemon Threads (守护线程)
守护线程倾向于提供一个通用的后台服务,但是不是你的程序必要的一部分。当所有的非守护线程完成了,那么这个程序就会终止,杀死所有的守护线程。反过来,如果有非守护线程在run则这个程序不会终止。
例子:
public class SimpleDaemons implements Runnable {
@Override
public void run() {
try {
while (true) {
TimeUnit.MILLISECONDS.sleep(100);
System.out.println(Thread.currentThread() + " " + this);
}
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("sleep() interrupted");
}
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(new SimpleDaemons());
thread.setDaemon(true);
thread.start();
}
System.out.println("all deomons started");
TimeUnit.MILLISECONDS.sleep(175);
}
}
你必须设置thread成为守护线程,在start()之前调用setDaemon()。
需要了解的部分:
1. 从守护线程中出生的线程也是守护线程;
例子:
class Daemon implements Runnable {
private Thread[] t = new Thread[10];
@Override
public void run() {
for (int i = 0; i < t.length; i++) {
t[i] = new Thread(new DaemonSpawn());
t[i].start();
System.out.println("daemon" + i + "started");
}
for (int i = 0; i < t.length; i++) {
System.out.println("i is deamon" + t[i].isDaemon());
}
while (true){
Thread.yield();
}
}
}
class DaemonSpawn implements Runnable {
@Override
public void run() {
while (true) {
Thread.yield();
}
}
}
public class Daemons{
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Daemon());
thread.setDaemon(true);
thread.start();
System.out.println("thread is deamon:" + thread.isDaemon());
TimeUnit.SECONDS.sleep(1);
}
}
2. 守护线程不会执行finally
public class DaemonsDontRunFinally {
public static void main(String[] args) {
Thread thread = new Thread(new ADaemon());
thread.setDaemon(true);
thread.start();
}
}
class ADaemon implements Runnable {
@Override
public void run() {
try {
System.out.println("running");
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("finally");
}
}
}
关于线程池:
尽量使用ThreadPoolExecutor,使用Exectors.newCachedThreadPool的内部实现也是使用的ThreadPoolExecutor。还是需要仔细了解!!!
本文介绍了多线程中的Sleeping、Priority和Daemon Threads概念。Sleeping通过调用sleep()让任务暂停执行;Priority允许设定线程优先级,但实际效果受CPU调度影响;Daemon Threads是后台服务线程,当所有非守护线程结束时,程序会终止。文章强调了不能依赖yield来控制任务顺序,并提醒读者理解守护线程的特性及其对程序终止的影响。
10万+

被折叠的 条评论
为什么被折叠?



