Java线程池例子

最近在研究大批量数据处理,在师傅的知道下采用了线程池,对我来说是一次质的飞跃:

 public void analyzeDealData()
        throws ParseException {
        // 第一步:创建表plan_res_mr_indoor plan_res_mr_outdoor
        System.out.println("111111第一步开始。。。。。");
        this.dao.createTable();
        System.out.println("111111第一步结束。。。。。");
        // 第二步:批量查处基础数据
        System.out.println("222222第二步开始。。。。。");
        this.dao.batchInserts();
        System.out.println("222222第二步结束。。。。。");
        // 第三步:分析处理outdoor 数据(使用多线程做)
        System.out.println("33333第三步开始。。。。。");
        ExecutorProcessPool pool = ExecutorProcessPool.getInstance();
        int count = this.dao.analyzeCellDataCount();
        int pageCount = count / 10000 + 1;
        for (int j = 0; j < pageCount; j++) {
            pool.execute(new AnalyzeDealByPage(j));
        }
        // 关闭线程池,如果是需要长期运行的线程池,不用调用该方法。
        // 监听程序退出的时候最好执行一下。
        pool.shutdown();
        System.out.println("33333第三步步结束。。。。。");
        
    }

//子线程

/**
     * 分析处理数据
     * 
     * @修改人 1527179267@qq.com
     * @版本号 0.0.1
     * @修改日期: 2016年12月20日 下午3:14:22
     * @see [相关类/方法]
     * @since [产品/模块版本]
     */
    class AnalyzeDealByPage implements Runnable {
        
        private int pageNumber;
        
        public AnalyzeDealByPage(int pageNumber) {
            this.pageNumber = pageNumber;
        }
        
        @Override
        public void run() {
            try {
                DateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
                int pageSize = 10000;
                int pageStartNumber = pageNumber * pageSize - 1;
                if (pageNumber == 0) {
                    pageStartNumber=0;
                }
                Map<String, Object> param = new HashMap<String, Object>();
                param.put("pageSize", pageSize);
                param.put("pageStartNumber", pageStartNumber);
                List<Map<String, Object>> outDoorList = dao.analyzeCellData(param);
                for (int i = 0, h = outDoorList.size() - 1; i < h; i++) {
                    Map<String, Object> itemOne = outDoorList.get(i);
                    Map<String, Object> itemTwo = outDoorList.get(i + 1);
                    String aboutEci = itemOne.get("eci") + "," + itemTwo.get("eci");
                    String timeBucket = itemOne.get("startTime") + "," + itemTwo.get("startTime");
                    Double journey =distance(Double.parseDouble(itemOne.get("lng").toString()),Double.parseDouble(itemOne.get("lat").toString()), Double.parseDouble(itemTwo.get("lng").toString()),Double.parseDouble(itemTwo.get("lat").toString()));
                    Long timDifference = Math.abs(fmt.parse(itemTwo.get("startTime").toString()).getTime()- fmt.parse(itemOne.get("startTime").toString()).getTime());
                    Double speed = journey / timDifference;
                    String endLng = itemTwo.get("lng").toString();
                    String endLat = itemTwo.get("lat").toString();
                    String endTime = itemTwo.get("startTime").toString();
                    itemOne.put("aboutEci", aboutEci);
                    itemOne.put("timeBucket", timeBucket);
                    itemOne.put("speed", speed);
                    itemOne.put("endLng", endLng);
                    itemOne.put("endLat", endLat);
                    itemOne.put("endTime", endTime);
                }
                System.out.println("批量更新开始。。。。。。"+(pageNumber+1)+"页更新");
                dao.batchUpdates(outDoorList);
                System.out.println("批量更新结束。。。。。。end***********************************************"+(pageNumber+1)+"页更新");
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
        
    }



在做很多高并发应用的时候,单线程的瓶颈已经满足不了我们的需求,此时使用多线程来提高处理速度已经是比较常规的方案了。在使用多线程的时候,我们可以使用线程池来管理我们的线程,至于使用线程池的优点就不多说了。

对于多线程的线程安全处理,这个也非常重要,有些同学还是要多补补课。

Java线程池说起来也简单,简单说下继承关系: 
ThreadPoolExecutor extends AbstractExecutorService implements ExecutorService extends Executor

还有一个支持延时执行线程和可以重复执行线程的实现类: 
ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService

大家把这些类中的相关方法弄清楚,使用线程池就不在话下了。其实弄清楚里面各个方法的功能也就够了。 
最重要的还是在实践中总结经验,企业需要的是能实际解决问题的人。

下面是我写的一个例子,包括3个Java文件,分别是: 
ExecutorServiceFactory.java 
ExecutorProcessPool.java 
ExecutorTest.java

下面贴出代码: 
1、ExecutorServiceFactory.java

package com.test.threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;


/**
 * 线程池构造工厂
 *
 * @author SHANHY(365384722@QQ.COM)
 * @date   2015年12月4日
 */
public class ExecutorServiceFactory {
    private static ExecutorServiceFactory executorFactory = new ExecutorServiceFactory();
    /**
     * 定时任务线程池
     */
    private ExecutorService executors;

    private ExecutorServiceFactory() {
    }

    /**
     * 获取ExecutorServiceFactory
     * 
     * @return
     */
    public static ExecutorServiceFactory getInstance() {
        return executorFactory;
    }

    /**
     * 创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
     * 
     * @return
     */
    public ExecutorService createScheduledThreadPool() {
        // CPU个数
        int availableProcessors = Runtime.getRuntime().availableProcessors();
        // 创建
        executors = Executors.newScheduledThreadPool(availableProcessors * 10, getThreadFactory());
        return executors;
    }

    /**
     * 创建一个使用单个 worker 线程的
     * Executor,以无界队列方式来运行该线程。(注意,如果因为在关闭前的执行期间出现失败而终止了此单个线程,
     * 那么如果需要,一个新线程将代替它执行后续的任务)。可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。与其他等效的
     * newFixedThreadPool(1) 不同,可保证无需重新配置此方法所返回的执行程序即可使用其他的线程。
     * 
     * @return
     */
    public ExecutorService createSingleThreadExecutor() {
        // 创建
        executors = Executors.newSingleThreadExecutor(getThreadFactory());
        return executors;
    }

    /**
     * 创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。调用
     * execute 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60
     * 秒钟未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资源。注意,可以使用 ThreadPoolExecutor
     * 构造方法创建具有类似属性但细节不同(例如超时参数)的线程池。
     * 
     * @return
     */
    public ExecutorService createCachedThreadPool() {
        // 创建
        executors = Executors.newCachedThreadPool(getThreadFactory());
        return executors;
    }

    /**
     * 创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数 nThreads
     * 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务
     * ,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止
     * ,那么一个新线程将代替它执行后续的任务(如果需要)。在某个线程被显式地关闭之前,池中的线程将一直存在。
     * 
     * @return
     */
    public ExecutorService createFixedThreadPool(int count) {
        // 创建
        executors = Executors.newFixedThreadPool(count, getThreadFactory());
        return executors;
    }


    /**
     * 获取线程池工厂
     * 
     * @return
     */
    private ThreadFactory getThreadFactory() {
        return new ThreadFactory() {
            AtomicInteger sn = new AtomicInteger();
            public Thread newThread(Runnable r) {
                SecurityManager s = System.getSecurityManager();
                ThreadGroup group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
                Thread t = new Thread(group, r);
                t.setName("任务线程 - " + sn.incrementAndGet());
                return t;
            }
        };
    }
}

 
 
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108

2、ExecutorProcessPool.java

package com.test.threadpool;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

/**
 * 线程处理类
 *
 * @author SHANHY(365384722@QQ.COM)
 * @date   2015年12月4日
 */
public class ExecutorProcessPool {

    private ExecutorService executor;
    private static ExecutorProcessPool pool = new ExecutorProcessPool();
    private final int threadMax = 10;

    private ExecutorProcessPool() {
        System.out.println("threadMax>>>>>>>" + threadMax);
        executor = ExecutorServiceFactory.getInstance().createFixedThreadPool(threadMax);
    }

    public static ExecutorProcessPool getInstance() {
        return pool;
    }

    /**
     * 关闭线程池,这里要说明的是:调用关闭线程池方法后,线程池会执行完队列中的所有任务才退出
     * 
     * @author SHANHY
     * @date   2015年12月4日
     */
    public void shutdown(){
        executor.shutdown();
    }

    /**
     * 提交任务到线程池,可以接收线程返回值
     * 
     * @param task
     * @return
     * @author SHANHY
     * @date   2015年12月4日
     */
    public Future<?> submit(Runnable task) {
        return executor.submit(task);
    }

    /**
     * 提交任务到线程池,可以接收线程返回值
     * 
     * @param task
     * @return
     * @author SHANHY
     * @date   2015年12月4日
     */
    public Future<?> submit(Callable<?> task) {
        return executor.submit(task);
    }

    /**
     * 直接提交任务到线程池,无返回值
     * 
     * @param task
     * @author SHANHY
     * @date   2015年12月4日
     */
    public void execute(Runnable task){
        executor.execute(task);
    }

}

 
 
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

3、ExecutorTest.java

package com.test.threadpool;

import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * 测试类
 *
 * @author SHANHY(365384722@QQ.COM)
 * @date   2015年12月4日
 */
public class ExecutorTest {

    public static void main(String[] args) {

        ExecutorProcessPool pool = ExecutorProcessPool.getInstance();

        for (int i = 0; i < 200; i++) {
            Future<?> future = pool.submit(new ExcuteTask1(i+""));
//          try {
//              如果接收线程返回值,future.get() 会阻塞,如果这样写就是一个线程一个线程执行。所以非特殊情况不建议使用接收返回值的。
//              System.out.println(future.get());   
//          } catch (Exception e) {
//              e.printStackTrace();
//          }
        }

        for (int i = 0; i < 200; i++) {
            pool.execute(new ExcuteTask2(i+""));
        }

        //关闭线程池,如果是需要长期运行的线程池,不用调用该方法。
        //监听程序退出的时候最好执行一下。
        pool.shutdown();
    }

    /**
     * 执行任务1,实现Callable方式
     *
     * @author SHANHY(365384722@QQ.COM)
     * @date   2015年12月4日
     */
    static class ExcuteTask1 implements Callable<String> {
        private String taskName;

        public ExcuteTask1(String taskName) {
            this.taskName = taskName;
        }

        @Override
        public String call() throws Exception {
            try {
//              Java 6/7最佳的休眠方法为TimeUnit.MILLISECONDS.sleep(100);
//              最好不要用 Thread.sleep(100);
                TimeUnit.MILLISECONDS.sleep((int)(Math.random() * 1000));// 1000毫秒以内的随机数,模拟业务逻辑处理
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("-------------这里执行业务逻辑,Callable TaskName = " + taskName + "-------------");
            return ">>>>>>>>>>>>>线程返回值,Callable TaskName = " + taskName + "<<<<<<<<<<<<<<";
        }
    }

    /**
     * 执行任务2,实现Runable方式
     *
     * @author SHANHY(365384722@QQ.COM)
     * @date   2015年12月4日
     */
    static class ExcuteTask2 implements Runnable {
        private String taskName;

        public ExcuteTask2(String taskName) {
            this.taskName = taskName;
        }

        @Override
        public void run() {
            try {
                TimeUnit.MILLISECONDS.sleep((int)(Math.random() * 1000));// 1000毫秒以内的随机数,模拟业务逻辑处理
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("-------------这里执行业务逻辑,Runnable TaskName = " + taskName + "-------------");
        }

    }
}

 
 
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90

上面代码中也有一些注释说明,自己把代码自己运行一遍看看效果。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值