- 浏览: 155027 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
西巴拉古呀那:
Linux多线程并发服务器编程(线程池,FTP服务器)网盘地址 ...
多线程服务器的适用场合 -
somefuture:
第四题怎麼用位图法。写了半天没出来,用了下面的,速度很快pri ...
位图法应用 -
寂寞秋江:
系统,全面,条理清晰,由浅入深,简直是集大成之作。 特别是最后 ...
单个进程最大线程数 -
darkjune:
有点意思, 不错
单个进程最大线程数 -
kidding87:
谢谢啦,收藏着
google使用一点敲门分享
在操作系统中,有两种不同的方法提供线程支持:用户层的用户线程,或内核层的内核线程。
其中用户线程在内核之上支持,并在用户层通过线程库来实现。不需要用户态/核心态切换,速度快。操作系统内核不知道多线程的存在,因此一个线程阻塞将使得整个进程(包括它的所有线程)阻塞。由于这里的处理器时间片分配是以进程为基本单位,所以每个线程执行的时间相对减少。
内核线程由操作系统直接支持。由操作系统内核创建、调度和管理。内核维护进程及线程的上下文信息以及线程切换。一个内核线程由于I/O操作而阻塞,不会影响其它线程的运行。
Java线程的实现是怎样的呢?我们通过SUN Java 6的源码了解其在Windows和Linux下的实现。
在Windows下的实现,os_win32.cpp中
bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
unsigned thread_id;
// Allocate the OSThread object
OSThread* osthread = new OSThread(NULL, NULL);
if (osthread == NULL) {
return false;
}
// Initial state is ALLOCATED but not INITIALIZED
{
MutexLockerEx ml(thread->SR_lock(), Mutex::_no_safepoint_check_flag);
osthread->set_state(ALLOCATED);
}
// Initialize support for Java interrupts
HANDLE interrupt_event = CreateEvent(NULL, true, false, NULL);
if (interrupt_event == NULL) {
delete osthread;
return NULL;
}
osthread->set_interrupt_event(interrupt_event);
osthread->set_interrupted(false);
thread->set_osthread(osthread);
if (stack_size == 0) {
switch (thr_type) {
case os::java_thread:
// Java threads use ThreadStackSize which default value can be changed with the flag -Xss
if (JavaThread::stack_size_at_create() > 0)
stack_size = JavaThread::stack_size_at_create();
break;
case os::compiler_thread:
if (CompilerThreadStackSize > 0) {
stack_size = (size_t)(CompilerThreadStackSize * K);
break;
} // else fall through:
// use VMThreadStackSize if CompilerThreadStackSize is not defined
case os::vm_thread:
case os::pgc_thread:
case os::cgc_thread:
case os::watcher_thread:
if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K);
break;
}
}
// Create the Win32 thread
//
// Contrary to what MSDN document says, "stack_size" in _beginthreadex()
// does not specify stack size. Instead, it specifies the size of
// initially committed space. The stack size is determined by
// PE header in the executable. If the committed "stack_size" is larger
// than default value in the PE header, the stack is rounded up to the
// nearest multiple of 1MB. For example if the launcher has default
// stack size of 320k, specifying any size less than 320k does not
// affect the actual stack size at all, it only affects the initial
// commitment. On the other hand, specifying 'stack_size' larger than
// default value may cause significant increase in memory usage, because
// not only the stack space will be rounded up to MB, but also the
// entire space is committed upfront.
//
// Finally Windows XP added a new flag 'STACK_SIZE_PARAM_IS_A_RESERVATION'
// for CreateThread() that can treat 'stack_size' as stack size. However we
// are not supposed to call CreateThread() directly according to MSDN
// document because JVM uses C runtime library. The good news is that the
// flag appears to work with _beginthredex() as well.
#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
#define STACK_SIZE_PARAM_IS_A_RESERVATION (0x10000)
#endif
HANDLE thread_handle =
(HANDLE)_beginthreadex(NULL,
(unsigned)stack_size,
(unsigned (__stdcall *)(void*)) java_start,
thread,
CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION,
&thread_id);
if (thread_handle == NULL) {
// perhaps STACK_SIZE_PARAM_IS_A_RESERVATION is not supported, try again
// without the flag.
thread_handle =
(HANDLE)_beginthreadex(NULL,
(unsigned)stack_size,
(unsigned (__stdcall *)(void*)) java_start,
thread,
CREATE_SUSPENDED,
&thread_id);
}
if (thread_handle == NULL) {
// Need to clean up stuff we've allocated so far
CloseHandle(osthread->interrupt_event());
thread->set_osthread(NULL);
delete osthread;
return NULL;
}
Atomic::inc_ptr((intptr_t*)&os::win32::_os_thread_count);
// Store info on the Win32 thread into the OSThread
osthread->set_thread_handle(thread_handle);
osthread->set_thread_id(thread_id);
// Initial thread state is INITIALIZED, not SUSPENDED
{
MutexLockerEx ml(thread->SR_lock(), Mutex::_no_safepoint_check_flag);
osthread->set_state(INITIALIZED);
}
// The thread is returned suspended (in state INITIALIZED), and is started higher up in the call chain
return true;
}
可以看出,SUN JVM在Windows下的实现,使用_beginthreadex来创建线程,注释中也说明了为什么不用“Window编程书籍推荐使用”的CreateThread函数。由此看出,Java线程在Window下的实现是使用内核线程。
摘自<<windows操作系统原理>>
内核线程:由操作系统内核创建和撤销,内核维护进程及线程的上下文信息以及线程的切换,一个内核线程由于I/O操作而阻塞,
不会影响其他线程的运行,windows NT和2000 支持内核线程。
用户线程:由应用进程利用线程库创建和管理,不依赖操作系统的核心,不需要用户态/内核态的切换,速度快,操作系统内核不知道
多线程的存在,因此一个线程阻塞将使得整个进程(包括它的所有的线程)阻塞,由于这里的处理器时间片分配是以进程为基本单位的。所以每个线程执行的时间相对减少。
而在Linux下又是怎样的呢?
在os_linux.cpp文件中的代码摘录如下:
bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) {
assert(thread->osthread() == NULL, "caller responsible");
// Allocate the OSThread object
OSThread* osthread = new OSThread(NULL, NULL);
if (osthread == NULL) {
return false;
}
// set the correct thread state
osthread->set_thread_type(thr_type);
// Initial state is ALLOCATED but not INITIALIZED
osthread->set_state(ALLOCATED);
thread->set_osthread(osthread);
// init thread attributes
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
// stack size
if (os::Linux::supports_variable_stack_size()) {
// calculate stack size if it's not specified by caller
if (stack_size == 0) {
stack_size = os::Linux::default_stack_size(thr_type);
switch (thr_type) {
case os::java_thread:
// Java threads use ThreadStackSize which default value can be changed with the flag -Xss
if (JavaThread::stack_size_at_create() > 0) stack_size = JavaThread::stack_size_at_create();
break;
case os::compiler_thread:
if (CompilerThreadStackSize > 0) {
stack_size = (size_t)(CompilerThreadStackSize * K);
break;
} // else fall through:
// use VMThreadStackSize if CompilerThreadStackSize is not defined
case os::vm_thread:
case os::pgc_thread:
case os::cgc_thread:
case os::watcher_thread:
if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K);
break;
}
}
stack_size = MAX2(stack_size, os::Linux::min_stack_allowed);
pthread_attr_setstacksize(&attr, stack_size);
} else {
// let pthread_create() pick the default value.
}
// glibc guard page
pthread_attr_setguardsize(&attr, os::Linux::default_guard_size(thr_type));
ThreadState state;
{
// Serialize thread creation if we are running with fixed stack LinuxThreads
bool lock = os::Linux::is_LinuxThreads() && !os::Linux::is_floating_stack();
if (lock) {
os::Linux::createThread_lock()->lock_without_safepoint_check();
}
pthread_t tid;
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);
pthread_attr_destroy(&attr);
if (ret != 0) {
if (PrintMiscellaneous && (Verbose || WizardMode)) {
perror("pthread_create()");
}
// Need to clean up stuff we've allocated so far
thread->set_osthread(NULL);
delete osthread;
if (lock) os::Linux::createThread_lock()->unlock();
return false;
}
// Store pthread info into the OSThread
osthread->set_pthread_id(tid);
// Wait until child thread is either initialized or aborted
{
Monitor* sync_with_child = osthread->startThread_lock();
MutexLockerEx ml(sync_with_child, Mutex::_no_safepoint_check_flag);
while ((state = osthread->get_state()) == ALLOCATED) {
sync_with_child->wait(Mutex::_no_safepoint_check_flag);
}
}
if (lock) {
os::Linux::createThread_lock()->unlock();
}
}
// Aborted due to thread limit being reached
if (state == ZOMBIE) {
thread->set_osthread(NULL);
delete osthread;
return false;
}
// The thread is returned suspended (in state INITIALIZED),
// and is started higher up in the call chain
assert(state == INITIALIZED, "race condition");
return true;
}
Java在Linux下的线程的创建,使用了pthread线程库,而pthread就是一个用户线程库,因此结论是,Java在Linux下是使用用户线程实现的。Linux 2.6内核的pthread实现为NPTL,和内核线程的映射是一对一。之前的Linux threads也是。
对于NPTL的一些介绍:
POSIX Thread Library (NPTL)使Linux内核可以非常有效的运行使用POSIX线程标准写的程序。这里有一个测试数据,在32位机下,NPTL成功启动100000个线程只用了2秒,而不使用NPTL将需要大约15分钟左右的时间。
历史
在内核2.6以前的调度实体都是进程,内核并没有真正支持线程。它是能过一个系统调用clone()来实现的,这个调用创建了一份调用进程的拷贝,跟fork()不同的是,这份进程拷贝完全共享了调用进程的地址空间。LinuxThread就是通过这个系统调用来提供线程在内核级的支持的(许多以前的线程实现都完全是在用户态,内核根本不知道线程的存在)。非常不幸的是,这种方法有相当多的地方没有遵循POSIX标准,特别是在信号处理,调度,进程间通信原语等方面。
很显然,为了改进LinuxThread必须得到内核的支持,并且需要重写线程库。为了实现这个需求,开始有两个相互竞争的项目:IBM启动的NGTP(Next Generation POSIX Threads)项目,以及Redhat公司的NPTL。在2003年的年中,IBM放弃了NGTP,也就是大约那时,Redhat发布了最初的NPTL。
NPTL最开始在redhat linux 9里发布,现在从RHEL3起内核2.6起都支持NPTL,并且完全成了GNU C库的一部分。
设计
NPTL使用了跟LinuxThread相同的办法,在内核里面线程仍然被当作是一个进程,并且仍然使用了clone()系统调用(在NPTL库里调用)。但是,NPTL需要内核级的特殊支持来实现,比如需要挂起然后再唤醒线程的线程同步原语futex.
NPTL也是一个1*1的线程库,就是说,当你使用pthread_create()调用创建一个线程后,在内核里就相应创建了一个调度实体,在linux里就是一个新进程,这个方法最大可能的简化了线程的实现。
除NPTL的1*1模型外还有一个m*n模型,通常这种模型的用户线程数会比内核的调度实体多。在这种实现里,线程库本身必须去处理可能存在的调度,这样在线程库内部的上下文切换通常都会相当的快,因为它避免了系统调用转到内核态。然而这种模型增加了线程实现的复杂性,并可能出现诸如优先级反转的问题,此外,用户态的调度如何跟内核态的调度进行协调也是很难让人满意。
对于pthread的更多理解可以参考:http://archive.cnblogs.com/a/1930707/
发表评论
-
阻塞同步 lock
2013-05-03 08:39 888转自:http://blog.csdn.net/chen7 ... -
阻塞同步synchronized
2013-05-03 08:40 1224转自:http://blog.csdn.net/chen7 ... -
关于中断处理
2013-05-03 08:41 853在历史上,Java试图提供过抢占式限制中断,但问题多多,例如前 ... -
wait和notify机制
2014-03-03 13:47 960Wait-Notify机制可以说是实现阻塞操作较为高效的一 ... -
lock和lockInterruptibly
2014-03-03 13:47 5212lockInterruptibly()允许在等待时由其他线程 ... -
流io 读
2014-03-03 13:47 6441. 关于InputStream.read() ... -
设计模式之不变模式(Immutable Pattern)分析
2014-03-06 10:55 789主要介绍编写不变类的主意事项: 归纳一下设计不变类的 5 ... -
jvm参数
2014-03-03 13:47 593作者:Ken Wu Email: ken.wu ... -
Java Object Initialization Order - Know your JLS!
2012-10-20 21:41 887转自:http://www.danielschneller.c ... -
jvm参数配置
2014-03-03 13:48 553/usr/local/jdk/bin/java -D ... -
读取Properties文件的六种方法
2014-03-14 10:11 6781。使用java.util.Properties类的load ... -
从Java视角理解伪共享(False Sharing)
2014-03-14 10:11 697从Java视角理解系统结构 ... -
从Java视角理解CPU缓存(CPU Cache)
2014-03-14 10:11 1128从Java视角理解系统结构 ... -
从Java视角理解CPU上下文切换(Context Switch)
2014-03-16 10:52 1677从Java视角理解系统结 ... -
浅谈JAVA ThreadPoolExecutor
2014-03-12 09:37 892基础 在我看来,java比C++的一个大好处就是提供了对 ... -
Java多线程同步如何从JVM的角度体会
2014-03-18 20:20 769我们在使用Java多线程 ... -
java 安全沙箱模型
2012-02-22 21:15 787起到第一道安全保障作 ... -
单个进程最大线程数
2012-01-10 10:09 28728原文链接:http://jzhihui.iteye.com/b ... -
简单的路径使用(转)
2011-12-03 11:38 718用JAVA获取文件,听似简单,但对于很多像我这样的新人来说,还 ...
相关推荐
java 查看JVM中所有的线程的活动状况 java 查看JVM中所有的线程的活动状况
JVM 的运行机制 多线程 JVM 的内存区域 JVM 会创建操作系统的接口创建一个原生线程。JVM 线程和操作系统线程是一一对应的
而每个线程创建时JVM都会为其创建工作内存 工作内存是每个线程的私有数据区域 而JAVA内存模型规定所有变量都存储在主内存 主内存是共享内存区域 所有线程都可以访问 但线程对变量的操作必须在工作内存中进行 ...
本文介绍了什么是Java,AIX下的Java版本,Java的性能准则,AIX提供的监视Java的工具,以及如何在AIX用户环境下进行Java应用程序性能调优。
JVM定义了若干个程序执行期间使用的数据区域。这个区域里的一些数据在JVM启动的时候创建,在JVM退出的时候销毁。其他的数据依赖于每一个线程,在线程创建的时候创建,在线程退出的时候销毁。
每一个 JVM 线程都拥有一个私有的 JVM 线程栈,用于存放当前线程的 JVM 栈帧(包括被调用函数的参数、局部变量和返回地址等)。如果某个线程的线程栈空间被耗尽,没有足够资源分配给新创建的栈帧,就会抛出 java....
1. Java API层:该层次就是我们最常接触的,平时使用Thread类,就是对应于这一个层次 2. JVM层:每一个Thread实例,在调用其start0
34个生产案例,还原真实的 JVM 问题现场!程序计数器、虚拟机栈、本地方法栈 3 个区域随线程生灭(因为是线程私有),栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作。而 Java 堆和方法区则不一样,...
jvmkill, 资源耗尽时终止 JVM 概述收费 jvmkill是一个简单的 JVMTI代理,在无法分配内存或者创建线程时强制终止 JVM 。 这对于可靠性目的很重要: 一个 OutOfMemoryError 常常会让JVM处于不一致状态。 终止JVM将允许...
JVM生命周期:JVM的生命周期始于启动一个Java程序,此时会创建一个JVM实例。程序中的public static void main(String[] args)方法作为JVM实例运行的起点。 垃圾收集:JVM具有自动内存管理和垃圾收集机制,用于自动...
2019最新深入理解JVM内存结构及运行原理(JVM调优)高级核心课程视频教程下载。JVM是Java知识体系中的重要部分,对JVM底层的了解是每一位Java程序员深入Java技术领域的重要因素。本课程试图通过简单易懂的方式,系统...
引用计数存储对特定对象的所有引用数,也就是说,当应用程序创建引用以及引用超出范围时,jvm必须适当增减引用数。当某对象的引用数为0时,便可以进行垃圾收集。 1.2.对象引用遍历 早期的jvm使用引用计数,现在...
守护线程如何创建?守护线程如何判断?守护线程使用的注意事项总结 什么是Java的守护线程( Daemon Thread )? Java 提供了两种类型的线程:守护线程 和 用户线程 用户线程 (User Thread) 是高优先级线程。JVM 会在...
Java虚拟机栈也是线程私有的,它的生命周期与线程...(当前大部分JVM都可以动态扩展,只不过JVM规范也允许固定长度的虚拟机栈) 3. Java虚拟机栈描述的是Java方法执行的内存模型:每个方法执行的同时会创建一个栈帧。
第5节jvm再体验-jvm可视化监控工具 [免费观看] 00:21:17分钟 | 第6节杂谈 [免费观看] 00:12:37分钟 | 第7节Java的发展历史00:27:24分钟 | 第8节Java的发展历史续00:02:27分钟 | 第9节Java技术体系00:08:46分钟 |...
JVM 内存区域 线程私有 程序计数器 当前线程所执行的字节码的行号指示器 对于 Java 方法,记录正在执行的虚拟机字节码指令的地址;对于 native 方法,记录值为空 (Undefined) 唯一一个Java 虚拟机规范中没有规定...
为守护线程是 JVM 自动创建的线程(但不一定),用户线程是程序创建的线程; 比如 JVM 的垃圾回收线程是一个守护线程,当所有线程已经撤离, 不再产生垃 圾,守护线程自然就没事可干了,当垃圾回收线程是 Java 虚拟...