Thinking In Java 之 多线程 1

来源:互联网 发布:大数据技术论文 编辑:程序博客网 时间:2024/06/04 22:17

Thinking In Java 之多线程

Using Executors

  1. The call to shutdown() prevents new task from being submitted to that Executor.
  2. Note that in any of the thread pools, existing threads are automatically reused when possible.
  3. A SingleThreadExecutor serializes the tasks that are submitted to it, and maintain its own (hidden) queue of pending task. SingleThreadExecutor to ensure that only one task at a time is running from any thread. This way, you don’t need to deal with synchronizing on the shared resource (and you won’t clobber the file system in the meantime).

Producing return values form tasks

class TaskWithResult implements Callable<String> {    private int id;    public TaskWithResult(int id) {        this.id = id;    }    public String call() {        return "result of TaskWithResult " + id;    }}public class CallableDemo {    public static void main(String[] args) {        ExecutorService exec = Executors.newCachedThreadPool();        ArrayList<Future<String>> results = new ArrayList<Future<String>>();        for (int i = 0; i < 10; i++) {            results.add(exec.submit(new TaskWithResult(i)));        }        for (Future<String> fs : results) {            try {                // get() blocks until completion:                System.out.println(fs.get());            } catch (InterruptedException e) {                e.printStackTrace();            } catch (ExecutionException e) {                e.printStackTrace();            } finally {                exec.shutdown();            }        }    }}

The overloaded Executors.callable() method tasks a Runnable and produces a Callable.

Sleeping

public class LiftOff implements Runnable {    protected int countDown = 10;    private static int taskCount = 0;//!    private final int id = taskCount++;//!    public LiftOff() {}    public LiftOff(int countDown) {        this.countDown = countDown;    }    public String status() {        return "#" + id + "(" + (countDown > 0 ? countDown : "Liftoff!" ) + "),";    }    @Override    public void run() {        while(countDown-- > 0) {            System.out.println(status());            // I've done the important parts of my cycle and this would be a good            // time to switch to another task for a while.            Thread.yield();        }    }}
public class SleepingTask extends LiftOff{    public void run() {        try {            while(countDown-- > 0) {                System.out.print(status());                TimeUnit.MILLISECONDS.sleep(100);            }        } catch (InterruptedException e) {            e.printStackTrace();        }    }    public static void main(String[] args) {        ExecutorService exec = Executors.newCachedThreadPool();        for(int i=0;i<5;i++) {            exec.execute(new SleepingTask());        }        exec.shutdown();      }}

Because exceptions won’t propagate across threads back to main(), you must locally handle any exceptions that arise within a task.

Priority

Lower-priority threads just tend to run less often.

public class SimplePrioroties implements Runnable{    private int countDown = 5;    private volatile double d;// No optimization    private int priority;    public SimplePrioroties(int priority) {        this.priority = priority;    }    public String toString() {        return Thread.currentThread() + ": " + countDown;    }    @Override    public void run() {        Thread.currentThread().setPriority(priority);//!        while(true) {            // An expensive, interruptable operation:            for(int i=1;i<10000;i++) {                d += (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 exec = Executors.newCachedThreadPool();        for(int i=0;i<5;i++) {            exec.execute(new SimplePrioroties(Thread.MIN_PRIORITY));        }        exec.execute(new SimplePrioroties(Thread.MAX_PRIORITY));        exec.shutdown();    }}

You can get a reference to the Thread object that is driving a task, inside that task, by calling Thread.currentThread().
Note that the priority is set at the beginning of run(); setting it in the constructor would do no good since the Executor has not begun the task at that point.

Daemon thread

public class SimpleDaemon 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 daemon = new Thread(new SimpleDaemon());            daemon.setDaemon(true);            daemon.start();        }        System.out.println("All daemon started");        TimeUnit.MILLISECONDS.sleep(175);    }}

When all of the non-daemon threads complete, the program is terminated, killing all daemon threads in the process.

以下例子使用到了ThreadFactory,可与上面的例子做对比。

public class DaemonThreadFactory implements ThreadFactory{    @Override    public Thread newThread(Runnable r) {        Thread t = new Thread(r);        t.setDaemon(true);        return t;    }}
public class DaemonFromFactory 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("Interrupted");        }    }    public static void main(String[] args) throws InterruptedException {        ExecutorService exec = Executors.newCachedThreadPool(new DaemonThreadFactory());        for(int i=0;i<10;i++) {            exec.execute(new DaemonFromFactory());        }        System.out.println("All daemons started");        TimeUnit.MILLISECONDS.sleep(500);    }}

——————————

public class DaemonsDontRunFinally {    public static void main(String[] args) {        Thread t = new Thread(new ADaemon());        t.setDaemon(true);        t.start();    }}class ADaemon implements Runnable{    @Override    public void run() {        try {            System.out.println("Starting ADaemon");            TimeUnit.SECONDS.sleep(1);        } catch (InterruptedException e) {            System.out.println("Exiting via InterruptedException");        }finally {            System.out.println();        }    }}

When you run this program, you’ll see that the finally clause is not executed, but if you comment out the call to setDaemon(), you’ll see the finally clause is executed.

Coding variations

即在构造器里启动自己

public class SimpleThread extends Thread {    private int countDown = 5;    private static int threadCount = 0;    public SimpleThread() {        // Store the Thread name:        super(Integer.toString(++threadCount));        start();    }    public String toString() {        return "#" + getName() + "(" + countDown + "),";    }    public void run() {        while(true) {            System.out.print(this);            if(--countDown == 0)                return;        }    }    public static void main(String[] args) {        for(int i=0;i<5;i++)             new SimpleThread();    }}
public class SelfManager implements Runnable{    private int countDown = 5;    private Thread t = new Thread(this);    public SelfManager() {        t.start();    }    public String toString() {        return Thread.currentThread().getName() + "(" + countDown + ")";    }    @Override    public void run() {        while(true) {            System.out.println(this);            if(--countDown == 0) {                return;            }        }    }    public static void main(String[] args) {        for(int i=0;i<5;i++) {            new SelfManager();        }    }}

This example is quite simple and therefore probably safe, but you should be aware that starting threads inside a constructor can be quite problematic, because another task might start executing before the constructor has completed, which means the task may be able to access the object in an unstable state.

Joining a thread

If a thread calls t.join() on another thread t, then the calling thread is suspended until the target thread t finished(when t.isAlive() is false).

class Sleeper extends Thread {    private int duration;    public Sleeper(String name, int sleepTime) {        super(name);        duration = sleepTime;        start();    }    public void run() {        try {            sleep(duration);        } catch (InterruptedException e) {            System.out.println(getName() + " was interrupted. " + "isInterrupted():  " + isInterrupted());            return;        }        System.out.println(getName() + "has awakened");    }}class Joiner extends Thread{    private Sleeper sleeper;    public Joiner(String name, Sleeper sleeper) {        super(name);        this.sleeper = sleeper;        start();    }    public void run() {        try {            sleeper.join();        } catch (InterruptedException e) {            System.out.println("Interrupted");        }        System.out.println(getName() + " join compeleted");    }}public class Joining {    public static void main(String[] args) {        Sleeper             sleepy = new Sleeper("Sleepy", 1500),            grumpy = new Sleeper("Grumpy", 1500);        Joiner             doper = new Joiner("Doper", sleepy),            doc = new Joiner("Doc", grumpy);        grumpy.interrupt();    }}

运行结果:
这里写图片描述
When another thread calls interrupt() on this thread, a flag is set to indicate that the thread has been interrupted. However, this flag is cleared when the exception is caught, so the result will always be false inside the catch clause.