Java线程与CPU核心的关系

 

今天写代码过程中,突然有个想法:我想知道Java线程执行在那个CPU核心上?或者说,我能控制我自己创建的线程运行在哪个CPU核心上?再或者说Java启动的线程和CPU核心的关系是什么样的,我能够自己定制吗?

或者有人问,你问这个问题有什么意思,这个又不用你关心。好吧,在Java平台上确实不用关心这些东西,你new一个Thread就可以直接运行了。现在的问题是我就想知道Java线程和CPU核心的执行关系,无关应用。

如果你确实想知道这个问题有什么用,我可以假设这么一个场景:已知自己创建的线程有两类,一类是IO密集型、一类是计算密集型,现在你想最大限度的使用CPU来分配这些线程,使得CPU的使用率最有效,现在我就可以分配CPU为一定数量的计算密集型和IO密集型,使得在每个CPU核心上均匀分配,而不是由系统分配;系统分配的话有可能会造成分布不均,使得CPU没有能够充分使用。

下面根据本文的成文思路开始叙述。

Java运行在虚拟机(Java Visual Machine, JVM)上,最有可能的就是JVM提供了这样的方法。对于JVM的运行状态,由xxxxMXBean表示,得到xxxxMXBean的方法有JavaManagementFactory提供,具体ManagementFactory的类包戳这里


ManagementFactory提供了多个获得JVM运行状态的类:

 

 

public static ClassLoadingMXBean getClassLoadingMXBean()
public static MemoryMXBean getMemoryMXBean()
public static ThreadMXBean getThreadMXBean()
public static RuntimeMXBean getRuntimeMXBean()
public static CompilationMXBean getCompilationMXBean()
public static OperatingSystemMXBean getOperatingSystemMXBean()
public static List<MemoryPoolMXBean> getMemoryPoolMXBeans()
public static List<MemoryManagerMXBean> getMemoryManagerMXBeans()
public static List<GarbageCollectorMXBean> getGarbageCollectorMXBeans()

 


其中返回的这些个MXBean,包括ClassLoadingMXBean、 MemoryMXBean、 ThreadMXBean、 RuntimeMXBeanCompilationMXBeanOperatingSystemMXBeanMemoryPoolMXBeanMemoryManagerMXBeanGarbageCollectorMXBean,根据名字,也能得到相应的含义,进而推断出这些Bean可能会具有的方法;比如OperatingSystemMXBean,能够得到关于操作系统的信息,其实也就仅限于namearchversionavailableProcessorssystemLoad等信息,没有再多的信息,这些信息都是JVM可以拿到的信息。其中和我们问题最为相关的是ThreadMXBean


那么ThreadMXBean中有哪些方法可能和我们的问题相关呢?我把ThreadMXBean方法全部列在这里:

 

 

public int getThreadCount();
public int getPeakThreadCount();
public long getTotalStartedThreadCount();  
public int getDaemonThreadCount();
public long[] getAllThreadIds();
public ThreadInfo getThreadInfo(long id);
public ThreadInfo[] getThreadInfo(long[] ids);
public ThreadInfo getThreadInfo(long id, int maxDepth);
public ThreadInfo[] getThreadInfo(long[] ids, int maxDepth);
public boolean isThreadContentionMonitoringSupported();
public boolean isThreadContentionMonitoringEnabled();
public void setThreadContentionMonitoringEnabled(boolean enable);
public long getCurrentThreadCpuTime();
public long getCurrentThreadUserTime();
public long getThreadCpuTime(long id);
public long getThreadUserTime(long id);
public boolean isThreadCpuTimeSupported();
public boolean isCurrentThreadCpuTimeSupported();
public boolean isThreadCpuTimeEnabled();
public void setThreadCpuTimeEnabled(boolean enable);
public long[] findMonitorDeadlockedThreads();
public void resetPeakThreadCount();
public long[] findDeadlockedThreads();
public boolean isObjectMonitorUsageSupported();
public boolean isSynchronizerUsageSupported();
public ThreadInfo[] getThreadInfo(long[]ids, boolean lockedMonitors,boolean lockedSynchronizers);
public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, boolean lockedSynchronizers);
 

 

浏览下ThreadMXBean的方法,发现这个bean是将虚拟机启动的线程统一管理了。从该bean中可以得到启动线程的信息,发现和CPU没有什么关系。和CPU有关系的CPUTime获取和我们的问题毫无关系,注意想获取CPUTine需要isThreadCpuTimeSupported();看来JVM并没有给我们提供这样的方便。

在这块问题追查过程中,发现了一个比较有趣的问题,这个问题我以前也不甚清楚:对于启动一个JVMJVM内部启动了几个线程呢?这个问题大家可以先考虑下,有时间的话我会在另外开文分析。



OK,也许是我知识量有限,求助于网络,看到stackoverflow上面的几个讨论,原来不只是我有这个疑问,大家也都对这个问题比较感兴趣。

 

 

http://stackoverflow.com/questions/974277/java-thread-running-on-which-processor

 

http://stackoverflow.com/questions/8956639/spin-a-processor-for-a-fixed-amount-of-cpu-time

 

http://stackoverflow.com/questions/2238272/java-thread-affinity

 

http://stackoverflow.com/questions/2758448/is-there-a-way-to-force-the-jvm-to-run-on-a-single-processor-or-core

 

 

看完这几篇讨论,结果应该呼之而出了。在Pure Java模型中,这个结果是No,至少对目前的JVM来说,这个功能没有支持,以后估计也不会支持。JVM的设计就是runs anywhere,屏蔽掉操作系统层面的概念,让你在JVM框架里完成自己需要的内容。而我的需求刚好是想通过JVM来控制我自己的运行程序运行在系统的哪个CPU核心上,这个应该是有违JVM设计的初衷,也许会在将来的高级API中提供这样的功能也说不定。

 

好吧,看到结果是No了,你肯定想离开了。不过我现在就是有这种优化要求,就是想将特定线程附加到特定的CPU上,怎么办?有什么变通的方法吗?

Pure Java不行,这个操作是操作系统层面的东西,我们需要调用操作系统的内容。这个首先想到的是JNI,没错,就是JNIJNIJava Native Interface)是sun(这个写Sun应该没错,尽管现在Java归属于Oracle)提供的java与系统中的原生方法交互的技术,使用JNI能帮助我们完成这个任务。这个任务对于C/C++来说就不是问题,将C/C++代码使用JNI调用,就能实现我们需要的功能。

这个线程附加到CPU核心的问题已经有人实现,看下github的这个地址:https://github.com/peter-lawrey/Java-Thread-Affinity,这个就能够实现我本文开始要求的功能,内容不错,推荐大家看看。

 

OK,本文到这里就算结束了,对于Java来说,处理常规的需求足够了,对于比较tricky and sticky的要求,就需要想办法解决,至少要知道其所以然。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值