- 浏览: 72836 次
- 性别:
- 来自: 北京
最新评论
-
zq3062211015:
想法很好。。万一 c就一个人下车 b很浪费啊
java并发学习之三:非阻塞漫想,关于环岛与地铁 -
zq3062211015:
楼主是大神,膜拜啊,不过有个地方说的不太对啊, if (poo ...
java并发学习之二:线程池(五) -
snake1987:
milk_36 写道终于找到是用java的了!LZ想问一下你们 ...
关于社交游戏中的同步服务器(长连接服务器) -
milk_36:
终于找到是用java的了!LZ想问一下你们项目中protobu ...
关于社交游戏中的同步服务器(长连接服务器) -
hobitton:
额,是我说的不准确哈,server不仅仅是options的集合 ...
java并发学习之二:线程池(四)
没找到什么好工具,也没得到好建议,好技巧,只能自己摸索了
一步步优化把
先是优化测试代码
加的内容不多,但挺关键的
测试要模拟的是一个平稳的任务下发过程(如同现实生活中的),所以一下子将所有任务丢到队列中是很不对的,而且数量一大,堆就满了
经过多次测试,决定通过让主线程每发送n个,就休息一段时间来降低主线程的下发频率
以达到平稳的目的
这样设置之后,再适当调一下,就可以让cpu利用率达到一个相对稳定的值了,从而可以更好地通过工具进行观察
然后是线程池代码
基本的改动是:
1.去掉了预启动线程
2.将wait,notify改为了用LockSupport,这样少了一个synchronized的消耗
3.将threadExecute方法改为了非阻塞
4.将command置为volatile
5.理顺了由busyThreadsNum的改变过程和改变的含义
谢谢
一步步优化把
先是优化测试代码
加的内容不多,但挺关键的
测试要模拟的是一个平稳的任务下发过程(如同现实生活中的),所以一下子将所有任务丢到队列中是很不对的,而且数量一大,堆就满了
经过多次测试,决定通过让主线程每发送n个,就休息一段时间来降低主线程的下发频率
以达到平稳的目的
这样设置之后,再适当调一下,就可以让cpu利用率达到一个相对稳定的值了,从而可以更好地通过工具进行观察
public class TestThreadPoolTest1 { public static void main(String[] args) throws InterruptedException { //testEasyRunnableThreadPool(new ThreadPoolTest1(10), 1000000, 10);//22553768552 //testEasyRunnableThreadPool(Executors.newFixedThreadPool(10), 1000000, 10);//2946477652 testEasyRunnableThreadPool(new ThreadPoolTest2(8), 10000000, 8); } /** * 一个产生随机数的方法,防止jvm优化 * @param seed * @return */ static int getRandomNum(int seed) { seed ^= (seed << 6); seed ^= (seed >>> 21); seed ^= (seed << 7); return seed; } /** * 任务是执行一个简单的计算,只占用cpu,没有io和其他阻塞的方法 */ static void testEasyRunnableThreadPool(Executor pool,int tryTime,int threadNum) throws InterruptedException { final AtomicInteger count = new AtomicInteger(0); //construct runnable Runnable command = new Runnable() { public void run() { final int addTime = 10000; long sum = 0; int temp = this.hashCode() ^ (int)System.currentTimeMillis(); for(int i = 0;i<addTime;i++) { sum += (temp = getRandomNum(temp)); } } }; testThreadPool(tryTime, pool, command); } static void testThreadPool(int tryNum,Executor pool,final Runnable command) throws InterruptedException { final CountDownLatch latch = new CountDownLatch(tryNum); final Random r = new Random(); Runnable wrapper = new Runnable() { public void run() { command.run(); //想测试并发,在并发中加入适当的同步操作是无法避免的,只能减少 //,在这,只是做了一个简单的countdown,影响不大 latch.countDown(); } }; long startTime = System.nanoTime(); //加一层循环 for(int j = 0;j<100000;j++) { for(int i = 0;i<tryNum/100000;i++) { pool.execute(wrapper); } //主线程休息 Thread.sleep(0, r.nextInt(50)); } long dispatchTime = System.nanoTime(); //加一个全部任务全部下发完的时间,与最终时间做对比 System.out.println(dispatchTime - startTime); latch.await(); long endTime = System.nanoTime(); System.out.println(endTime-startTime); } }
然后是线程池代码
基本的改动是:
1.去掉了预启动线程
2.将wait,notify改为了用LockSupport,这样少了一个synchronized的消耗
3.将threadExecute方法改为了非阻塞
4.将command置为volatile
5.理顺了由busyThreadsNum的改变过程和改变的含义
public class ThreadPoolTest2 implements Executor { //等待队列 Queue<Runnable> waitingQueue = null; ConcurrentLinkedQueue<ThreadNode> freeThread; //相当于一个freeThread的状态,根据状态决定行为,原则上将freeThread.size()+busyThreadsNum=MAXTHREADNUM private AtomicInteger busyThreadsNum = new AtomicInteger(0); //最大线程数 final int MAXTHREADNUM; public ThreadPoolTest2 (int threadNum) { this.MAXTHREADNUM = threadNum; init(MAXTHREADNUM,new ConcurrentLinkedQueue<Runnable>()); } private void init(int threadNum,ConcurrentLinkedQueue<Runnable> queue) { freeThread = new ConcurrentLinkedQueue<ThreadNode>(); waitingQueue = queue; } //去掉了synchronized private void threadExecute(Runnable command) { for(;;) { //得到开始的值 int expect = busyThreadsNum.get(); //由于else中先执行了busyThreadsNum.incrementAndGet();才添加,所以会出现 //busyThreadsNum为MAXTHREADNUM,但实际的运行数量少于busyThreadsNum,少1,但这种 //现象是本应如此的 if(expect == MAXTHREADNUM) { waitingQueue.add(command); return; } else { busyThreadsNum.incrementAndGet(); ThreadNode t = freeThread.poll(); if(t == null) { t = new ThreadNode(); t.setCommand(command); t.start(); return; } t.setCommand(command); LockSupport.unpark(t); } } } private class ThreadNode extends Thread { //加了线程保证可见性,因为根据处理逻辑,只会有一个线程进行修改,所以只需要保证可见性就可以了 //同时,由于之前用的不是LockSupport,所以wait或者await还有notify或者signal都是需要加锁的 //之前没加volatile,是由于使用了额外的同步(在wait,notify之前用了synchronized),所以 //相当于加入了一个synchronized with关系,所以command变为可见了(setCommand操作发生在同步之前) volatile Runnable command = null; Exception e = null; public ThreadNode() { } Exception getException() { return e; } void setCommand(Runnable c) { command = c; } @Override public void run() { try { for(;;) { if(command == null) { ThreadPoolTest2.this.waitThread(this); continue; } command.run(); command = ThreadPoolTest2.this.getCommand(); } }catch (InterruptedException e) { } } } Runnable getCommand() throws InterruptedException { return waitingQueue.poll(); } void waitThread(ThreadNode t) throws InterruptedException { //先往队列中放,再减少busyThreadsNum //因为即使busyThreadsNum已经为MAXTHREADNUM了,但其实队列中有空闲的线程 //这也是允许的,造成的问题最严重不过往等待任务队列里面添加了不该等待,而是马上执行的任务 //而且只是瞬间的 freeThread.offer(t); busyThreadsNum.getAndDecrement(); LockSupport.park(t); } protected void beforeExecute() { } public void execute(Runnable command) { beforeExecute(); threadExecute(command); afterExecute(); } protected void afterExecute() { } }
评论
2 楼
snake1987
2011-04-12
leeing.org 写道
偶然路过,发现你的文章很不错!支持一下!
谢谢
1 楼
leeing.org
2011-04-09
偶然路过,发现你的文章很不错!支持一下!
发表评论
-
关于jdk7的aio
2012-11-28 13:59 0最近耳边老有人提jdk7的 ... -
关于锁的两个小技巧
2012-09-03 14:55 1394现在我们的开发中越来越多用锁的情况,锁其实比cas恐怖很多,像 ... -
关于java hotspot vm的server版和client版的一点小事
2012-09-03 14:53 4130我们知道,java的虚拟器其实是有两个版本的, client ... -
关于游戏脚本
2012-09-03 14:43 2246社交游戏其实不是太需 ... -
关于社交游戏中的同步服务器(长连接服务器)
2012-09-03 14:39 7521博客好久没打理了,今 ... -
关于游戏中的同步服务器(长连接服务器)
2012-09-03 14:33 1博客好久没打理了,今 ... -
BTrace实践
2011-10-13 15:30 0一直都在关注java的profile工具,这几天发现了这个好东 ... -
项目回忆(一):虚拟房间系统
2011-09-23 14:34 1431需求: 1.硬件环境:所有 ... -
近月学习记录(四)
2011-09-12 12:48 0基于netty的同步游戏服 ... -
近月学习记录(三)
2011-09-10 15:01 0最近在用netty做一个交 ... -
protobuf深入分析
2011-07-22 19:31 0公司用了protobuf,在日常工作中都有所接触,一直没有时间 ... -
近月学习记录(二)
2011-06-12 22:30 01.maven maven其实不难,但是一开始学习的时候的确感 ... -
近月学习记录(一)
2011-06-12 22:27 2457最近换了一个公司,确 ... -
java并发学习之二:线程池(五)
2011-04-17 13:31 2667之前的线程池已实现了基本的功能:运行每一个线程,而且测试了一下 ... -
java并发学习之六:JCSP(Java Communicating Sequential Processes)实践
2011-04-13 11:32 5856首先得描述下什么是JCSP ... -
java并发学习之二:线程池(四)
2011-04-12 17:43 2387一直都知道有两个jvm,一个是server,一个是client ... -
java并发学习之五:读JSR133笔记
2011-04-06 11:33 10904在写线程池的时候,遇到了很多的问题,特别是happen-bef ... -
java并发学习之四:JSR 133 (Java Memory Model) FAQ【译】
2011-04-01 16:52 4090Jsr133地址:http://www.c ... -
java并发学习之三:非阻塞漫想,关于环岛与地铁
2011-03-27 21:10 1811到过北京上地的都会知道,上地城铁往西走有一个很大的上地环岛,旁 ... -
java并发学习之二:线程池(二)
2011-03-24 09:43 2330在看书的时候看到了一个观察死锁的工具TDA(Thread Du ...
相关推荐
Java并发编程中的线程池是提高系统效率的关键工具,它解决了频繁创建和销毁线程的问题。线程池通过复用已存在的线程来处理任务,从而避免了每次任务执行完毕后销毁线程的开销。在Java中,线程池的核心实现是`java....
Java并发编程中的JUC线程池是Java程序员必须掌握的关键技术之一,它允许开发者高效地管理并发执行的任务,充分利用多核处理器的性能。线程池的出现解决了在并发环境中线程创建、销毁带来的开销,提高了系统资源的...
线程池是Java多线程编程中的重要概念,它是一种管理线程的机制,通过池化技术有效地管理和控制线程的生命周期,以提高系统资源的...通过持续学习和实践,我们可以更好地驾驭线程池,提升系统的并发处理能力和响应速度。
Java8并行流中自定义线程池操作示例 Java8并行流中自定义线程池操作示例主要介绍了Java8并行流中自定义线程池操作,结合实例形式分析了并行流的相关概念、定义及自定义线程池的相关操作技巧。 1. 概览 Java8引入了...
Java并发编程实践中的线程池是一个关键的概念,它在多线程编程中扮演着至关重要的角色,有效地管理和调度线程资源,以提高系统的性能和效率。线程池通过复用已存在的线程来减少线程的创建和销毁开销,避免了频繁的上...
线程池是Java并发编程的核心技术之一,它通过复用一组预创建的线程来执行任务,从而减少了创建和销毁线程的开销,提高了系统的响应速度和处理能力。 #### 线程池的作用 线程池可以显著提高多线程应用的性能和效率...
《Java并发编程:设计原则与模式(第二版)》是一本深入探讨Java多线程编程技术的权威著作。这本书详细阐述了在Java平台中进行高效并发处理的关键概念、设计原则和实用模式。以下是对该书内容的一些核心知识点的概述...
在Java编程中,线程池是一种管理线程资源的有效方式,它可以提高...在阅读《聊聊并发(3)Java线程池的分析和使用》这份文档时,你可以学习到更多关于线程池的实践技巧和案例分析,这对于提升Java开发能力大有裨益。
Java 并发学习笔记: 进程和线程, 并发理论, 并发关键字, Lock 体系, 原子操作类, 发容器 & 并发工具, 线程池, 并发实践 Java是一种面向对象的编程语言,由Sun Microsystems于1995年推出。它是一种跨平台的...
Java并发编程是Java开发中的重要领域,特别是在大型系统和服务器端应用中,高效地利用多核处理器资源,实现高并发性能至关重要。...通过深入学习和实践,开发者可以更好地驾驭Java并发,提升程序的性能和稳定性。
Java线程池是一种高效管理线程资源的工具,它能够帮助开发者有效地控制并调度线程,从而提升系统性能,减少系统资源的浪费。...通过深入学习和实践,我们可以更好地利用线程池来优化我们的Java应用程序。
Java并发编程是提升系统性能的关键,理解并熟练运用线程池可以有效地管理线程资源,提高系统的响应速度和并发能力。在实际项目中,合理设计和配置线程池,结合具体业务需求,能够使程序运行更加稳定、高效。通过阅读...
Java线程池是一种高级的多线程处理框架,它是Java并发编程中非常重要的一个组件。线程池的原理和实现涉及到操作系统调度、内存管理和并发控制等多个方面。理解线程池的工作原理有助于优化程序性能,避免过度创建和...
《Java并发编程的艺术》这本书是Java开发者深入理解并发编程的重要参考书籍。这本书全面地介绍了Java平台上的并发和多线程编程技术,旨在帮助开发者解决在实际工作中遇到的并发问题,提高程序的性能和可伸缩性。 ...
1. **线程池的组成**:线程池主要由工作线程、任务队列和控制机制三部分构成。工作线程负责执行任务,任务队列用于存储待处理的任务,控制机制则负责管理线程池的大小和任务的分配。 2. **线程池的优点**: - **...
《Java并发编程实战》是Java并发编程领域的一本经典著作,它深入浅出地介绍了如何在Java平台上进行高效的多线程编程。这本书的源码提供了丰富的示例,可以帮助读者更好地理解书中的理论知识并将其应用到实际项目中。...
通过学习《Java并发编程:设计原则与模式(第二版)》,开发者可以掌握Java并发编程的核心技术和最佳实践,提升在多线程环境下的编程能力。书中的实例和实战经验将帮助读者在实际开发中避免常见的并发陷阱,编写出...
### JAVA线程池原理及几种...综上所述,线程池是Java并发编程中的一个重要概念,它可以帮助开发者更高效地管理线程资源,提高应用程序的性能。理解线程池的工作原理及其配置细节,对于构建高性能的并发应用至关重要。
Java线程池封装是Java并发编程中重要的一环,合理的线程池配置和封装能显著提升程序的性能和稳定性。理解线程池的工作原理,根据业务需求选择合适的参数,以及正确处理拒绝策略,都是实现高效并发处理的关键。在实际...
通过深入学习"Java并发编程与实践"文档,开发者能够提升自己在高并发环境下的编程能力,设计出更加健壮和高效的Java应用程序。这份资料对于理解Java并发原理、优化并发代码和解决并发问题具有极大的价值。