分享

java多线程、线程池的实现

 天才白痴书馆 2015-04-16
Java实现多线程的3种方法:继承Thread类、实现runnable接口、使用ExecutorService,Callable、Future实现有返回值的多线程。前2种线程的实现方式没有返回值,第三种实现方式可以获取线程执行的返回值。

一:继承java.lang.Thread类

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println( "my thread begin." );
        try {
            // 休眠1000毫秒
            Thread.sleep( 1000 );
        } catch ( InterruptedException e ) {
            e.printStackTrace();
        }
        System.out.println( "my thread over." );
    }
    public static void main( String[] args ) {
        MyThread thread = new MyThread();
        thread.start();
    }
}

 

二:实现java.lang.Runnable接口

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println( "my thread begin." );
        try {
            // 休眠1000毫秒
            Thread.sleep( 1000 );
            // do something...
        } catch ( InterruptedException e ) {
            e.printStackTrace();
        }
        System.out.println( "my thread over." );
    }
    public static void main( String[] args ) {
        Thread thread = new Thread( new MyThread() );
        thread.start();
    }
}
实现Runnable接口会比继承Thread类更灵活一些,因为Java是单继承,继承了一个类就不能再继承另外一个类,而接口可以实现多个。但是无论是继承Thread类还是实现Runnable接口都不能获取多线程的返回值,除非借助额外的变量,在run方法中修改一个变量,在其他地方使用这个变量,这种实现方式比较"鸡肋"。

三:实现java.util.concurrent.Callable接口

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class MyThread implements Callable<object> {
    @Override
    public Object call() throws Exception {
        System.out.println( "my thread begin." );
        try {
            // 休眠1000毫秒
            Thread.sleep( 1000 );
        } catch ( InterruptedException e ) {
            e.printStackTrace();
        }
        System.out.println( "my thread over." );
        return "ok";
    }
    public static void main( String[] args ) {
        // 创建一个线程池
        ExecutorService pool = Executors.newFixedThreadPool( 2 );
        Future<object> f = pool.submit( new MyThread() );
        //关闭线程池
        pool.shutdown();
        try {
            System.out.println( f.get() );
        } catch ( InterruptedException e ) {
            e.printStackTrace();
        } catch ( ExecutionException e ) {
            e.printStackTrace();
        };
    }
}</object></object>

 

 

通过创建一个线程池提交一个Callable任务就可以通过Future类来获取线程的返回值了,调用Future的get()方法的时候,如果任务没有完成则阻塞直到任务完成。正如get()的注释:Waits if necessary for the computation to complete, and then retrieves its result.

 

 

上面代码中的ExecutorService接口继承自Executor接口,Executor的实现基于生产者-消费者模式。提交任务的执行者是生产者(产生待完成的工作单元),执行任务的线程是消费者(消耗掉这些工作单元)。如果要实现一个生产者-消费者的设计,使用Executor通常是最简单的方式。

Executors类提供了几种创建线程池的方法,通过Exectors创建的线程池也实现了ExecutorService接口,方法如下:

1、固定大小的线程池:newFixedThreadPool(int nThreads)

 

创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

2、单任务线程池:Executors.newSingleThreadExecutor()

 

创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

3、可变尺寸的线程池:Executors.newCachedThreadPool()

创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

4、延迟线程池:Executors.newScheduledThreadPool(int corePoolSize)

创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

 

注意:shutdown()方法并不是终止线程的执行,而是禁止在这个Executor中添加新的任务。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多