并发

173 阅读3分钟

创建多线程方法

  • new Thread(runnable).start

  • Executors.newCachedThreadPool().execute(runnable)

    与命令模式类似,只需要暴露run方法。其他的交给ExecutorService处理

从任务中产生返回值

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) {
                System.out.println(e);
                return;
            } catch(ExecutionException e) {
                System.out.println(e);
            } finally {
                exec.shutdown();
            }
    }
}

休眠 sleep

  • Thread.sleep(ms);
  • TimeUnit.MILLISECONDS.sleep(100);
  • sleep只能让当前线程休眠。

Daemon

后台任务,会随着主线程的结束,而被强制终止。

class ADaemon implements Runnable {
    public void run() {
        try {
            print("Starting ADaemon");
            TimeUnit.SECONDS.sleep(1);
        } catch(InterruptedException e) {
            print("Exiting via InterruptedException");
        } finally {
            print("This should always run?");
        }
    }
}
public class DaemonsDontRunFinally {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(new ADaemon());
        t.setDaemon(true);
        t.start();
    }
}
//comment
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 that the finally clause is executed. 
这种突然终止,they are rarely a good idea。

加入一个线程 join

在线程a中,调用线程b.join时,a暂停,直到b结束。
在b运行的时候,可以调用b.interrupt(),之后b抛出InterruptedException,在抛出后isInterrupted()依然为false。

异常捕获

在新建的线程里抛出异常,不能在主线程里面被捕获。

    /*
*  an uncaught exception.
* */
public class ExceptionThread implements Runnable {
    public void run() {
        throw new RuntimeException();
    }
    public static void main(String[] args) {
        //如果没有下面一行代码,trycatch无法捕获异常。
        //Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        ExecutorService exec = Executors.newCachedThreadPool();
        try {
            exec.execute(new ExceptionThread());
        } catch (Exception e) {
            System.out.println("dont throw");
        }
    }
}

class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("caught exception");
    }
}

以上为Thread绑定静态的异常处理器。也可以手动为每个线程绑定单独的异常处理器。

/*
* exceptions got caught.
* */
public class CaptureUncaughtException {
    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool(
                new HandlerThreadFactory());
        exec.execute(new ExceptionThread2());
    }


    /*
    * 以下代码作用:
    * 新建ThreadFactory,作为线程池的参数。
    * 再该工厂类中,为每个线程增加异常处理器 t.setUncaughtExceptionhandler(new MyUncaughtExceptionHandler)
    * 需要新建MyUncaughtExceptionHandler类
    * */

    private static class HandlerThreadFactory implements ThreadFactory {
        public Thread newThread(Runnable r) {
            System.out.println(this + " creating new Thread");
            Thread t = new Thread(r);
            System.out.println("created " + t);
            t.setUncaughtExceptionHandler(
                    new MyUncaughtExceptionHandler());
            System.out.println(
                    "eh = " + t.getUncaughtExceptionHandler());
            return t;
        }
        /*
        *
        * */
        private class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("caught exception");
            }
        }
    }

    private static class ExceptionThread2 implements Runnable {
        public void run() {
            Thread t = Thread.currentThread();
            System.out.println("run() by " + t);
            System.out.println(
                    "eh = " + t.getUncaughtExceptionHandler());
            throw new RuntimeException();
        }
    }
} 

终结任务

线程的状态:
* new , 初始化完成,等待CPU时间。
* runnable 就绪状态,在runnable状态,只要调度器给cpu时间,就运行,不给cpu就不运行。这不同于死亡和阻塞状态。
* blocked 阻塞,阻塞状态时不会得到cpu时间。有某个条件阻止它运行。
* dead 死亡状态,终止状态不再是可调度的。再也不会得到cpu时间,但是任务还可以被中断。
  • executorService.shutdown

    shutdown 关闭线程池。线程池不能传入新的线程,但是正在执行的线程会继续执行。

    shutdown之后调用awaitTermination(250,TimeUnit.MILLSECONDS),主线程阻塞250ms,等待线程池结束,全部结束返回true。shutdown方法调用后,就不能再继续使用ExecutorService来追加新的任务了,如果继续调用execute方法执行新的任务的话就会抛出RejectedExecutionException异常

可重入性

是指外层方法获得锁是,内层方法自动获得锁。要不然会导致死锁。

  • 同一个方法是可重入的
  • 不同的方法是可重入的
  • 在子类同步方法中,调用父类的同步方法是,是可重入的。