java线程池资源同步用过的内存资源不释放 是正常现象吗

下次自动登录
现在的位置:
& 综合 & 正文
Java大量线程运行时,减少内存占用量方法
项目发布到Production服务器上,经过一段时间跟踪发现服务器上项目的内存占有量在缓慢增长,但是在本地做压力时却没有发现这个问题,或者虽然做了压力测试单由于环境的差异内存增长不明显所以没有注意。于是就下载了JProfilter安装到本地的测试服务器上,运行测试发现有些类的个数竟然大于并发线程的个数,很是奇怪,经分析发现原来这并发线程都使用New
Class来实现一些对底层数据或对象的操作,代码如下:  public void run() {  try {  ...  OpenidAccount userData = new OpenidServices().getOpenidAccount(this.openid);  ...  } catch (Exception e) {  ...  } finally {  ...  }  }  以上代码在线程结束后,创建的new OpenidServices()对象 虽然没有再被其它对象引用,但是它需要等待JVM回收,这样当有大批量并发线程出现时就有可能不能得到及时释放,造成系统内存大量占用。  分析源码后发现可以把这个方法修改为静态方法,  public class OpenidServices {  public static OpenidAccount getOpenidAccount(String openidURL) throws Exception {  if (StringUtils.isNotEmpty(openidURL)) {  ...  }else {    }  }  }  此时每个线程的调用都无需再New一个新对象出来,仅需调用该类的静态方法就可以了。  OpenidAccount userData = OpenidServices.getOpenidAccount(this.openid);  所以考试大觉得在多线程代码中尽可能的减少创建新对象的个数,如果可能尽可能使用单例对象、工具类或静态方法,这样可以减少内存的占用量
&&&&推荐文章:
【上篇】【下篇】JAVA内存释放机制 - CSDN博客
JAVA内存释放机制
和内存释放(主要是GC)有关的话题。
  ★JVM的内存?
  在虚拟机规范中(具体章节请看“这里 ”),提及了如下几种类型的内存空间:
  ◇栈内存(Stack):每个线程私有的。
  ◇堆内存(Heap):所有线程公用的。
  ◇方法区(MethodArea):有点像以前常说的“进程代码段”,这里面存放了每个加载类的反射信息、类函数的代码、编译时常量等信息。
  ◇原生方法栈(Native Method Stack):主要用于JNI中的原生代码,平时很少涉及。
  ★垃圾回收机制简介?
  其实Java虚拟机规范中并未规定垃圾回收的相关细节。垃圾回收具体该怎么搞,完全取决于各个JVM的设计者。所以,不同的JVM之间,GC的行为可能会有一定的差异。下面咱拿SUN官方的JVM来简单介绍一下GC的机制。
  ◇啥时候进行垃圾回收?
  一般情况下,当JVM发现堆内存比较紧张、不太够用时,它就会着手进行垃圾回收工作。但是大伙儿要认清这样一个残酷的事实:JVM进行GC的时间点是无法精确预知的。因为GC启动的时刻会受到各种运行环境因素的影响,随机性太大。
  虽说咱们无法精确预知,但假如你想知道每次垃圾回收执行的情况,还是蛮方便的。可以通过JVM的命令行参数“-XX:+PrintGC”把相关信息打印出来。
  另外,调用System.gc()只是建议JVM进行GC。至于JVM到底会不会做,那就不好说啦。通常不建议自己手动调用System.gc(),还是让JVM自行决定比较好。另外,使用JVM命令行参数“-XX:+DisableExplicitGC”可以让System.gc()不起作用。
  ◇谁来负责垃圾回收?
  一般情况下,JVM会有一个或多个专门的垃圾回收线程,由它们负责清理回收垃圾内存。
  ◇如何发现垃圾对象?
  垃圾回收线程会从“根集(Root Set)”开始进行对象引用的遍历。所谓的“根集”,就是正在运行的线程中,可以访问的引用变量的集合(比如所有线程当前函数的参数和局部变量、当前类的成员变量等等)。垃圾回收线程先找出被根集直接引用的所有对象(不妨叫集合1),然后再找出被集合1直接引用的所有对象(不妨叫集合2),然后再找出被集合2直接引用的所有对象......如此循环往复,直到把能遍历到的对象都遍历完。
  凡是从根集通过上述遍历可以到达的对象,都称为可达对象或有效对象;反之,则是不可达对象或失效对象(也就是垃圾)。
  ◇如何清理/回收垃圾?
  通过上述阶段,就把垃圾对象都找出来。然后垃圾回收线程会进行相应的清理和回收工作,包括:把垃圾内存重新变为可用内存、进行内存的整理以消除内存碎片、等等。这个过程会涉及到若干算法,有爱好的同学可以参见“这里”。限于篇幅,咱就不深入聊了。
  ◇分代
  早期的JVM是不采用分代技术的,所有被GC管理的对象都存放在同一个堆里面。这么做的缺点比较明显:每次进行GC都要遍历所有对象,开销很大。其实大部分的对象生命周期都很短(短命对象),只有少数对象比较长寿;在这些短命对象中,又只有少数对象占用的内存空间大;其它大量的短命对象都属于小对象(很符合二八原理 )。
   有鉴于此,从JDK 1.2之后,JVM开始使用分代的垃圾回收(Generational GarbageCollection)。JVM把GC相关的内存分为年老代(Tenured)和年轻代(Nursery)、持久代(Permanent,对应于JVM规范的方法区)。大部分对象在刚创建时,都位于年轻代。假如某对象经历了几轮GC还活着(大龄对象),就把它移到年老代。另外,假如某个对象在创建时比较大,可能就直接被丢到年老代。经过这种策略,使得年轻代总是保存那些短命的小对象。在空间尺寸上,年轻代相对较小,而年老代相对较大。
  因为有了分代技术,JVM的GC也相应分为两种:主要收集(Major Collection)和次要收集(MinorCollection)。主要收集同时清理年老代和年轻代,因此开销很大,不常进行;次要收集仅仅清理年轻代,开销很小,经常进行。
  ★GC对性能会有啥影响??
  刚才介绍了GC的大致原理,那GC对性能会造成哪些影响捏?主要有如下几个方面:
  ◇造成当前运行线程的停顿
  早期的GC比较弱智。在它工作期间,所有其它的线程都被暂停(以免影响垃圾回收工作)。等到GC干完活,其它线程再继续运行。所以,早期JDK的GC一旦开始工作,整个程序就会陷入假死状态,失去各种响应。
  经过这些年的技术改进(包括采用分代技术),从JDK1.4开始,GC已经比较精明了。在它干活期间,只是偶然暂停一下其它线程的运行(从长时间假死变为暂时性休克)。
  ◇遍历对象引用的开销
  试想假如JVM中的对象很多,那遍历完所有可达对象肯定是比较费劲的工作,这个开销可不小。
  ◇清理和回收垃圾的开销
  遍历完对象引用之后,对垃圾的清理和回收也有较大的开销。这部分开销可能包括复制内存块、更新对象引用等等。
  ★几种收集器?
  ◇两个性能指标
  因为今天聊的是性能的话题,必然会提到衡量GC性能的两个重要指标:吞吐量(Throughput)和停顿时间(PauseTime)。吞吐量这个词不是很直观,解释一下:就是JVM不用于GC的时间占总时间的比率。吞吐量是越大越好,停顿时间是越小越好。
  不同的应用程序对这两个指标的关注点不一样(后面具体会说),也就是所谓的“众口难调”。很多JVM厂商为了迎合“众口”,不得不提供多种几种垃圾收集器供使用者选择。不同的收集器,采用的收集策略是不一样的,下面具体介绍。
  ◇串行收集器(Serial Collector)
  使用命令行选项“-XX:+UseSerialGC”指定。
  这种收集器是最传统的收集器。它使用单线程进行垃圾回收,对于单CPU机器比较合适。另外,小型应用或者对上述两个指标没有非凡要求的,可以使用串行收集器。
  ◇并行收集器(Parallel Throughput Collector)
  顾名思义,这种收集器使用多个线程进行垃圾回收以达到高吞吐量。垃圾回收线程的数量通过命令行选项“-XX:ParallelGCThreads=n”指定。可以设置该数值以便充分利用多CPU/多核。
  当使用命令行选项“-XX:+UseParallelGC”时:它会针对年轻代使用多个垃圾回收线程,对年老代依然使用单个线程的串行方式。此选项最早在JDK1.5引入。
  当使用命令行选项“-XX:+UseParallelOldGC”时:它针对年轻代和年老代都使用多个垃圾回收线程的方式。不过此选项从JDK1.6才开始引入。
  ◇并发收集器(Concurrent Low Pause Collector)
  使用命令行选项“-XX:+UseConcMarkSweepGC”指定。
  这种收集器优先保证程序的响应。它会尽量让垃圾回收线程和应用自身的线程同时运行,从而降低停顿时间。此选项从JDK1.4.1开始支持。
  ◇增量收集器(Incremental Collector)
  自从JDK 1.4.2以来,SUN官方就停止维护该收集器了。所以俺就节省点口水,不多说了。
  ★如何降低GC的影响??
  ◇尽量减少堆内存的使用
  由于GC是针对存储在堆内存的对象进行的。咱们假如在程序中减少引用对象的分配(也就相应降低堆内存分配),那对于提高GC的性能是很有帮助滴。上次“字符串过滤实战”的帖子给出了一个例子,示范了如何通过降低堆内存的分配次数来提升性能。
  ◇设置合适的堆内存大小
  JVM的堆内存是有讲究的,不能太大也不能太小。假如堆内存太小,JVM老是感觉内存不够用,可能会导致频繁进行垃圾回收,影响了性能;假如堆内存太大,以至于操作系统的大部分物理内存都被JVM自个儿霸占了,那可能会影响其它应用程序甚至操作系统本身的性能。
  另外,年轻代的大小(或者说年轻代与年老代的比值)对于GC的性能也有明显影响。假如年轻代太小,可能导致次要收集很频繁;假如年轻代太大,导致次要收集的停顿很明显。
  JVM提供了若干和堆内存大小相关的命令行选项,具体如下:
------------------------------
-Xms  设置初始堆内存
-Xmx  设置最大堆内存
-Xmn  设置年轻代的大小
-XX:NewRatio=n  设置年轻代与年老代的比例为“n”
-XX:NewSize=n  设置年轻代大小为“n”
------------------------------
  一般情况下,JVM的默认参数值已经够用。所以没事儿别轻易动用上述选项。假如你非调整不可,一定要做深入的性能对比测试,保证调整后的性能确实优于默认参数值。
  ◇吞吐量和停顿的取舍
  前面提到了不同应用的众口难调。常见的口味有两种:(1)看重吞吐量,对停顿时间无所谓;(2)侧重于停顿时间。
  对于某些在后台的、单纯运算密集型的应用,属于第一种。比如某些科学计算的应用。这时候建议使用并行收集器。
  对于涉及用户UI交互的、实时性要求比较高、程序需要快速响应的,属于第二种。比如某些桌面游戏、某些电信交换系统。这时候建议使用并发收集器。
  ★相关的参考资料?
  ◇GC调优资料
  SUN官方提供了若干关于JVM垃圾回收调优的说明文档,JDK 1.4.2请看“这里 ”;JDK 1.5请看“这里 ”;JDK1.6请看“这里 ”。
  ◇JVM命令行选项说明
  这是SUN公司内的某个有心人整理的各种命令行参数大全,在“这里 ”。包括有每个参数所适用的JDK版本。
  ◇虚拟机规范
  “这里 ”是SUN官方的JVM规范。
本文已收录于以下专栏:
相关文章推荐
很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C、C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确...
和内存释放(主要是GC)有关的话题。
  ★JVM的内存?
  在Java虚拟机规范中(具体章节请看“这里 ”),提及了如下几种类型的内存空间:
  ◇栈内存(Stack):每个线程私有的...
1 如果一块内存区域能够重复利用,最好不要申请新的。这个内存区域有可能是系统的一个类,自己的一个内部有数组元素,或者能够放大量数据的结构。
2 最好不要在循环里面申请内存,循环越大,越坏事。换句话说...
1 如果一块内存区域能够重复利用,最好不要申请新的。这个内存区域有可能是系统的一个类,自己的一个内部有数组元素,或者能够放大量数据的结构。2 最好不要在循环里面申请内存,循环越大,越坏事。换句话说,申...
l归纳起来,对象清除的途径有:
 (1) 依靠Java的垃圾回收机制回收内存空间。
 (2) 调用System.gc()方法,请求垃圾回收。
 (3) Java系统开始运行时,自动调用java....
垃圾收集的目的在于清除不再使用的对象。gc通过确定对象是否被活动对象引用来确定是否收集该对象。gc首先要判断该对象是否是时候可以收集。两种常用的方法是引用计数和对象引用遍历。
引用计数 每个对象都含...
java做的系统给人的印象是什么?占内存!说道这句话就会有N多人站出来为java辩护,并举出一堆的性能测试报告来证明这一点。其实从理论上来讲java做的系统并不比其他语言开发出来的系统更占用内存,那么...
原文出自【雪的痕迹】
原文地址:/cwbwebhome/article/article8/852.html
java做的系统给人的印象是什么?占内存!...
的内存管理就是对象的分配和释放问题。
中,程序员需要通过关键字
为每个对象申请内存空间
他的最新文章
讲师:吴岸城
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)登录以解锁更多InfoQ新功能
获取更新并接收通知
给您喜爱的内容点赞
关注您喜爱的编辑与同行
966,690 九月 独立访问用户
语言 & 开发
架构 & 设计
文化 & 方法
您目前处于:
聊聊并发(三)——JAVA线程池的分析和使用
聊聊并发(三)——JAVA线程池的分析和使用
26&他的粉丝
日. 估计阅读时间:
:Facebook、Snapchat、Tumblr等背后的核心技术
相关厂商内容
相关赞助商
ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, milliseconds,runnableTaskQueue, handler);
创建一个线程池需要输入几个参数:
corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。
runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。 可以选择以下几个阻塞队列。
ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
PriorityBlockingQueue:一个具有优先级的无限阻塞队列。
maximumPoolSize(线程池最大大小):线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。
ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。
RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略。
AbortPolicy:直接抛出异常。
CallerRunsPolicy:只用调用者所在线程来运行任务。
DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
DiscardPolicy:不处理,丢弃掉。
当然也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。
keepAliveTime(线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。
TimeUnit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。
向线程池提交任务
我们可以使用execute提交的任务,但是execute方法没有返回值,所以无法判断任务是否被线程池执行成功。通过以下代码可知execute方法输入的任务是一个Runnable类的实例。
threadsPool.execute(new Runnable() {
public void run() {
// TODO Auto-generated method stub
我们也可以使用submit 方法来提交任务,它会返回一个future,那么我们可以通过这个future来判断任务是否执行成功,通过future的get方法来获取返回值,get方法会阻塞住直到任务完成,而使用get(long timeout, TimeUnit unit)方法则会阻塞一段时间后立即返回,这时有可能任务没有执行完。
Future&Object& future = executor.submit(harReturnValuetask);
Object s = future.get();
} catch (InterruptedException e) {
// 处理中断异常
} catch (ExecutionException e) {
// 处理无法执行任务异常
} finally {
// 关闭线程池
executor.shutdown();
线程池的关闭
我们可以通过调用线程池的shutdown或shutdownNow方法来关闭线程池,它们的原理是遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程,所以无法响应中断的任务可能永远无法终止。但是它们存在一定的区别,shutdownNow首先将线程池的状态设置成STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表,而shutdown只是将线程池的状态设置成SHUTDOWN状态,然后中断所有没有正在执行任务的线程。
只要调用了这两个关闭方法的其中一个,isShutdown方法就会返回true。当所有的任务都已关闭后,才表示线程池关闭成功,这时调用isTerminaed方法会返回true。至于我们应该调用哪一种方法来关闭线程池,应该由提交到线程池的任务特性决定,通常调用shutdown来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow。
线程池的分析
流程分析:线程池的主要工作流程如下图:
从上图我们可以看出,当提交一个新任务到线程池时,线程池的处理流程如下:
首先线程池判断基本线程池是否已满?没满,创建一个工作线程来执行任务。满了,则进入下个流程。
其次线程池判断工作队列是否已满?没满,则将新提交的任务存储在工作队列里。满了,则进入下个流程。
最后线程池判断整个线程池是否已满?没满,则创建一个新的工作线程来执行任务,满了,则交给饱和策略来处理这个任务。
源码分析。上面的流程分析让我们很直观的了解了线程池的工作原理,让我们再通过源代码来看看是如何实现的。线程池执行任务的方法如下:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
//如果线程数小于基本线程数,则创建线程并执行当前任务
if (poolSize &= corePoolSize || !addIfUnderCorePoolSize(command)) {
//如线程数大于等于基本线程数或线程创建失败,则将当前任务放到工作队列中。
if (runState == RUNNING && workQueue.offer(command)) {
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);
//如果线程池不处于运行中或任务无法放入队列,并且当前线程数量小于最大允许的线程数量,
则创建一个线程执行任务。
else if (!addIfUnderMaximumPoolSize(command))
//抛出RejectedExecutionException异常
reject(command); // is shutdown or saturated
工作线程。线程池创建线程时,会将线程封装成工作线程Worker,Worker在执行完任务后,还会无限循环获取工作队列里的任务来执行。我们可以从Worker的run方法里看到这点:
public void run() {
Runnable task = firstT
firstTask =
while (task != null || (task = getTask()) != null) {
runTask(task);
} finally {
workerDone(this);
合理的配置线程池
要想合理的配置线程池,就必须首先分析任务特性,可以从以下几个角度来进行分析:
任务的性质:CPU密集型任务,IO密集型任务和混合型任务。
任务的优先级:高,中和低。
任务的执行时间:长,中和短。
任务的依赖性:是否依赖其他系统资源,如数据库连接。
任务性质不同的任务可以用不同规模的线程池分开处理。CPU密集型任务配置尽可能小的线程,如配置Ncpu+1个线程的线程池。IO密集型任务则由于线程并不是一直在执行任务,则配置尽可能多的线程,如2*Ncpu。混合型的任务,如果可以拆分,则将其拆分成一个CPU密集型任务和一个IO密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐率要高于串行执行的吞吐率,如果这两个任务执行时间相差太大,则没必要进行分解。我们可以通过Runtime.getRuntime().availableProcessors()方法获得当前设备的CPU个数。
优先级不同的任务可以使用优先级队列PriorityBlockingQueue来处理。它可以让优先级高的任务先得到执行,需要注意的是如果一直有优先级高的任务提交到队列里,那么优先级低的任务可能永远不能执行。
执行时间不同的任务可以交给不同规模的线程池来处理,或者也可以使用优先级队列,让执行时间短的任务先执行。
依赖数据库连接池的任务,因为线程提交SQL后需要等待数据库返回结果,如果等待的时间越长CPU空闲时间就越长,那么线程数应该设置越大,这样才能更好的利用CPU。
建议使用有界队列,有界队列能增加系统的稳定性和预警能力,可以根据需要设大一点,比如几千。有一次我们组使用的后台任务线程池的队列和线程池全满了,不断的抛出抛弃任务的异常,通过排查发现是数据库出现了问题,导致执行SQL变得非常缓慢,因为后台任务线程池里的任务全是需要向数据库查询和插入数据的,所以导致线程池里的工作线程全部阻塞住,任务积压在线程池里。如果当时我们设置成无界队列,线程池的队列就会越来越多,有可能会撑满内存,导致整个系统不可用,而不只是后台任务出现问题。当然我们的系统所有的任务是用的单独的服务器部署的,而我们使用不同规模的线程池跑不同类型的任务,但是出现这样问题时也会影响到其他任务。
线程池的监控
通过线程池提供的参数进行监控。线程池里有一些属性在监控线程池的时候可以使用
taskCount:线程池需要执行的任务数量。
completedTaskCount:线程池在运行过程中已完成的任务数量。小于或等于taskCount。
largestPoolSize:线程池曾经创建过的最大线程数量。通过这个数据可以知道线程池是否满过。如等于线程池的最大大小,则表示线程池曾经满了。
getPoolSize:线程池的线程数量。如果线程池不销毁的话,池里的线程不会自动销毁,所以这个大小只增不+ getActiveCount:获取活动的线程数。
通过扩展线程池进行监控。通过继承线程池并重写线程池的beforeExecute,afterExecute和terminated方法,我们可以在任务执行前,执行后和线程池关闭前干一些事情。如监控任务的平均执行时间,最大执行时间和最小执行时间等。这几个方法在线程池里是空方法。如:
protected void beforeExecute(Thread t, Runnable r) { }
Java并发编程实战。
JDK1.6源码
方腾飞,花名清英,淘宝资深开发工程师,关注并发编程,目前在广告技术部从事无线广告联盟的开发和设计工作。个人博客: 微博: 欢迎通过我的微博进行技术交流。
感谢对本文的审校。
给InfoQ中文站投稿或者参与内容翻译工作,请邮件至。也欢迎大家通过新浪微博()或者腾讯微博()关注我们,并与我们的编辑和其他读者朋友交流。
Author Contacted
语言 & 开发
49 他的粉丝
0 他的粉丝
0 他的粉丝
0 他的粉丝
0 他的粉丝
1169 他的粉丝
0 他的粉丝
告诉我们您的想法
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
Re: 拜读,有一些困惑望解答
Re: 拜读,有一些困惑望解答
Re: 拜读,有一些困惑望解答
能谈谈thread pool和多核CPU的关系吗? 怎样能保证thread pool的配置,让其能够最大化的压栈多核cpu
Re: 能谈谈thread pool和多核CPU的关系吗? 怎样能保证thread pool的配置,让其能够最大化的压栈多核cpu
Re: 能谈谈thread pool和多核CPU的关系吗? 怎样能保证thread pool的配置,让其能够最大化的压栈多核cpu
Re: 能谈谈thread pool和多核CPU的关系吗? 怎样能保证thread pool的配置,让其能够最大化的压栈多核cpu
使用的一些问题?
不知道是不是错误
Re: 使用的一些问题?
Re: 不知道是不是错误
昨晚再次阅读了该文,有几个问题需要解答
Re: 昨晚再次阅读了该文,有几个问题需要解答
SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
Re: 咨询问题
SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一
线程池里的线程是如何复用的
Re: 线程池里的线程是如何复用的
Re: 咨询问题
SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一
能不能不要乱写误人子弟!
Re: 能不能不要乱写误人子弟!
taskCount释义有误
有一些疑问,望博主解答
请教一下线程销毁的问题
Re: 请教一下线程销毁的问题
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p
当有人回复此评论时请E-mail通知我
赞助商链接
InfoQ每周精要
订阅InfoQ每周精要,加入拥有25万多名资深开发者的庞大技术社区。
架构 & 设计
文化 & 方法
<及所有内容,版权所有 &#169;
C4Media Inc.
服务器由 提供, 我们最信赖的ISP伙伴。
北京创新网媒广告有限公司
京ICP备号-7
找回密码....
InfoQ账号使用的E-mail
关注你最喜爱的话题和作者
快速浏览网站内你所感兴趣话题的精选内容。
内容自由定制
选择想要阅读的主题和喜爱的作者定制自己的新闻源。
设置通知机制以获取内容更新对您而言是否重要
注意:如果要修改您的邮箱,我们将会发送确认邮件到您原来的邮箱。
使用现有的公司名称
修改公司名称为:
公司性质:
使用现有的公司性质
修改公司性质为:
使用现有的公司规模
修改公司规模为:
使用现在的国家
使用现在的省份
Subscribe to our newsletter?
Subscribe to our industry email notices?
我们发现您在使用ad blocker。
我们理解您使用ad blocker的初衷,但为了保证InfoQ能够继续以免费方式为您服务,我们需要您的支持。InfoQ绝不会在未经您许可的情况下将您的数据提供给第三方。我们仅将其用于向读者发送相关广告内容。请您将InfoQ添加至白名单,感谢您的理解与支持。}

我要回帖

更多关于 java手动释放内存 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信