Thinking In Java 之 多线程 1

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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值