后台线程相关知识

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 休眠
 * 影响任务的行为的一种简单方法是调用sleep,这将使任务中止执行给定的时间。在LiftOff类中,要是把对yield的调用换成调用sleep
 * 对sleep的调用可以抛出InterruptedException异常,并且你可以看到,它在run中被捕获,因为异常不能跨线程传播回main,所以你必须在本地处理所有的任务
 * 内部产生的异常
 *
 * 每个任务都将要睡眠(阻塞),这使得线程调度器可以切换到另一个线程,进而驱动另一个任务。顺序行为依赖于底层的线程机制,这种机制在不同的操作系统之间是有差异的,
 * 因此,你不能依赖于它,如果你必须控制任务执行的顺序,那么最好的就是使用同步控制,或者在某些情况下,压根不使用线程,但是要编写自己的协同例程,
 * 这些例程将会按照指定的顺序在互相之间传递控制权。
 */
public class SleepingTask extends LiftOff{

    public void run(){
        try{
            while (countDown-- > 0) {
                System.out.println(status());
                TimeUnit.MILLISECONDS.sleep(100);
            }
        } catch(InterruptedException e){
            System.err.println("Interrupted");
        }
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            executorService.execute(new SleepingTask());
        }
        executorService.shutdown();
    }
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 优先级
 * 线程的优先级将该线程的重要性传递给了调度器。尽管CPU处理现有线程集的顺序是不确定的,
 * 但是调度器将倾向于让优先权最高的线程先执行。然而,这并不是意味着优先权较低的线程将得不到执行
 * (优先权不会导致死锁).优先级较低的线程仅仅是执行的频率较低。
 *
 * 在绝大多少时间里,所有线程都应该以默认的优先级运行,试图操纵线程优先级通常是一种错误。
 *
 * 1.线程的可见性:当一个线程修改一个共享变量时,另外一个线程能读到这个修改的值。
 * 2. 顺序一致性:禁止指令重排序。
 * 
 * 在run里,执行了100000次开销相当大的浮点运算,包括double类型的加法与除法。
 * 变量d是volatile的 以努力确保不进行任何编译器优化。如果没有加入这些运算的话,
 * 就看不见设置优先级的效果,有了这些运算,就能观察到优先级为MAX_PRIORITY的线程
 * 被线程调度器优先选择,尽管向控制台打印也是开销较大的操作,但在那种情况下看不见优先级的
 * 效果,因为向控制台打印不能被中断,而数学运算是可以终端的,这里运算时间足够的长,因此线程调度
 * 机制才来得及
 * 介入,交换任务并关注优先级,使得最高优先级线程被有限选择。
 * 尽管JDK有10个优先级,但它与多数操作系统都不能映射得很好,比如Window有7个优先级且不是固定的,所以这种映射关系也是不确定的,Sun的
 * Solaris有2的31个优先级,唯一可移植的是当调整优先级的时候,只使用MAX_PRIORITY NORM_PRIORITY和MIN_PRIORITY三种级别
 */
public class SimplePriorities implements Runnable{

    private int countDown = 5;
    private volatile double d; //确保不进行任何编译器优化。
    private int priority;

    public SimplePriorities(int priority) {
        this.priority = priority;
    }

    public String toString() {
        // 打印线程的名称,线程的优先级以及线程所属的线程组。
        // 你可以通过构造器来自己设置这个名称
        return Thread.currentThread() +": " +countDown; //返回当前线程 Thread.currentThread()是Thread的一个静态方法 用于获取当前线程对象的一个引用
    }

    @Override
    public void run() {
        Thread.currentThread().setPriority(priority); //设置优先级
        while (true) {
            for (int i = 1; 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 static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 5; i++) {
            executorService.execute(new SimplePriorities(Thread.MIN_PRIORITY));
        }

        executorService.execute(new SimplePriorities(Thread.MAX_PRIORITY));

        executorService.shutdown();
    }
}

让步
如果知道已经完成了在run方法的循环的一次迭代过程中所需的工作,就可以给线程调度机制一个暗示:你的工作已经注意的差不多了,可以让别的线程使用CPU了。这个暗示将通过调用yield方法来作出。当调用yield时,你也是在建议具有相同优先级的其他线程可以运行。
LiftOff.java使用yield在各种不同的LiftOff任务之间产生分布良好的处理机制。尝试着注释掉LiftOff.run中的Thread.yield,以查看区别。但是,大体上,对于任何重要的控制或在调整应用时,都不能依赖于yield。实际上,yield经常被误用。
后台线程

import sun.awt.windows.WPrinterJob;

import java.util.concurrent.TimeUnit;
import net.mindview.util.*;

/**
 * 后台线程
 * 所谓后台线程,是指在程序运行的时候再后台提供一种通用服务的线程,并且这种线程并不属于程序中
 * 不可或缺的部分。因此,当所有的非后台线程结束时,程序也就终止了,同时会杀死进程中的所有后台线程。
 * 反过来说,只要有任何非后台线程还在运行,程序就不会终止。比如,执行main就是一个非后台程序。
 *
 * 必须在线程启动之前调用setDaemon方法,才能设置它为后台线程。
 * 一旦main完成其工作,就没什么能阻止程序终止了,因为除了后台程序之外,已经没有线程在运行了。
 * main线程被设定为短暂睡眠,所以可以观察到所有后台线程启动后的结果不这样的话,你就只能看见
 * 一些后台线程创建时得到的结果,
 */
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) {
            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);//守护线程 确保主方法结束时候,子线程随之结束(默认是false
            thread.start();
        }
        System.out.printf("All daemons started");
        TimeUnit.MILLISECONDS.sleep(175);
    }
}

SimpleDaemons创建了显式的线程,以便可以设置他们后台标志。通过编写定制的ThreadFactory可以定制Executor创建的线程的属性(后台,优先级,名称)

import java.util.concurrent.ThreadFactory;
 /**
 * 该接口的目的是定制一个线程,可以设置线程的优先级、名字、是否后台线程、状态等。
  */
public class DaemonThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
        Thread thread = new Thread(r);
        thread.setDaemon(true);
        return thread;
    }
}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/*
这与普通的ThreadFactory的唯一差异就是它将后台状态全部设置为了true
你现在可以用一个新的DaemonThreadFactory作为参数传递给Executor.newCachedThreadFactoryPool
 */
public class DaemonFromFactory implements Runnable{
    @Override
    public void run() {
        try {
            TimeUnit.MILLISECONDS.sleep(100);
            System.out.println(Thread.currentThread()+" " + this);
        } catch (InterruptedException e) {
            System.out.println("Interrupted");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool(new DaemonThreadFactory());
        for (int i = 0; i < 10; i++) {
            executorService.execute(new DaemonFromFactory());
        }
        System.out.println("All daemons started");
        TimeUnit.MILLISECONDS.sleep(500);
    }
}

每个静态的ExecutorService创建方法都被重载为接受一个ThreadFactory对象将被用来创建新的线程

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 每个静态的ExecutorService创建方法都被重载为接受一个ThreadFactory对象,而这个对象将被用来创建新的线程
 */
public class DaemonTreadPoolExecutor extends ThreadPoolExecutor {
    public DaemonTreadPoolExecutor() {
        super(0,Integer.MAX_VALUE,60L,TimeUnit.SECONDS,new SynchronousQueue<Runnable>(),new DaemonThreadFactory());
    }
 }
import java.util.concurrent.TimeUnit;

/**
 * 可以通过isDaemon方法来确定线程是否是一个后台线程,
 * 如果是一个后台线程,那么它创建的任何线程将被自动设置成后台线程
 *
 * Daemon线程被设置成了后台线程,然后派生出许多子线程,这些线程
 * 并没有被显式地设置为后台模式,不过他们确是后台线程,接着Daemon线程
 * 进入了无限循环,并在循环里调用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("d.isDaemon = "+thread.isDaemon()+", ");
        TimeUnit.SECONDS.sleep(1);
    }
}
/**
 *
 */
public 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("DaemonSpawn "+ i + " started ");
        }

        for (int i = 0; i < t.length; i++) {
            System.out.println("t["+i+"]. isDaemon() ="+t[i].isDaemon()+". ");
        }
        while (true)
            Thread.yield();
    }
}
public class DaemonSpawn implements Runnable {

    @Override
    public void run() {
        while (true)
            Thread.yield();
    }
}

你可能感兴趣的:(java,算法,jvm)