- 浏览: 159639 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
西巴拉古呀那:
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 931转自:http://blog.csdn.net/chen7 ... -
阻塞同步synchronized
2013-05-03 08:40 1273转自:http://blog.csdn.net/chen7 ... -
关于中断处理
2013-05-03 08:41 885在历史上,Java试图提供过抢占式限制中断,但问题多多,例如前 ... -
wait和notify机制
2014-03-03 13:47 1034Wait-Notify机制可以说是实现阻塞操作较为高效的一 ... -
lock和lockInterruptibly
2014-03-03 13:47 5268lockInterruptibly()允许在等待时由其他线程 ... -
流io 读
2014-03-03 13:47 6731. 关于InputStream.read() ... -
设计模式之不变模式(Immutable Pattern)分析
2014-03-06 10:55 843主要介绍编写不变类的主意事项: 归纳一下设计不变类的 5 ... -
jvm参数
2014-03-03 13:47 629作者:Ken Wu Email: ken.wu ... -
Java Object Initialization Order - Know your JLS!
2012-10-20 21:41 920转自:http://www.danielschneller.c ... -
jvm参数配置
2014-03-03 13:48 593/usr/local/jdk/bin/java -D ... -
读取Properties文件的六种方法
2014-03-14 10:11 7261。使用java.util.Properties类的load ... -
从Java视角理解伪共享(False Sharing)
2014-03-14 10:11 739从Java视角理解系统结构 ... -
从Java视角理解CPU缓存(CPU Cache)
2014-03-14 10:11 1191从Java视角理解系统结构 ... -
从Java视角理解CPU上下文切换(Context Switch)
2014-03-16 10:52 1719从Java视角理解系统结 ... -
浅谈JAVA ThreadPoolExecutor
2014-03-12 09:37 931基础 在我看来,java比C++的一个大好处就是提供了对 ... -
Java多线程同步如何从JVM的角度体会
2014-03-18 20:20 793我们在使用Java多线程 ... -
java 安全沙箱模型
2012-02-22 21:15 819起到第一道安全保障作 ... -
单个进程最大线程数
2012-01-10 10:09 28841原文链接:http://jzhihui.iteye.com/b ... -
简单的路径使用(转)
2011-12-03 11:38 745用JAVA获取文件,听似简单,但对于很多像我这样的新人来说,还 ...
相关推荐
在探究JVM线程状态以及Thread.sleep的实现原理时,我们首先需要了解Java线程与操作系统线程之间的关系。在Java虚拟机(JVM)中,每个线程通常都是以一对一的关系映射到操作系统线程上的。然而,尽管两者在实现上是...
首先,Java提供了`java.lang.management.ThreadMXBean`接口,它是管理JVM线程的管理接口。通过这个接口,我们可以获取线程的各种信息,包括线程ID、线程名称、线程状态等。线程状态主要有以下几种: 1. 新建(NEW)...
- 分析线程堆栈,减少不必要的线程创建,优化同步策略,避免死锁和资源争抢。 5. **其他监控工具:** - `jconsole`和`VisualVM`提供图形化的JVM监控,包括内存、线程、类加载等信息。 - `jcmd`是JDK自带的命令行...
一个线程可以创建和撤销另一个线程;同一进程中的多个线程之间可以并发执行。多线程是指在一个程序中同时存在多个线程,这些线程共享相同的内存空间,但拥有独立的堆栈和局部变量,能够在多核处理器上并行执行,从而...
这本书详细介绍了Java中的并发编程,包括JVM线程的创建、管理和同步。其中,线程的生命周期(新建、就绪、运行、阻塞和死亡)是基础,而线程同步则通过`synchronized`关键字、`wait()`, `notify()`和`notifyAll()`...
本文将探讨如何在Windows环境下通过简单的命令行工具来监控JVM实例的数量,以及如何进行线程测试,特别是在单例模式下的JVM实例验证。 首先,了解如何监控JVM实例数量。在Windows操作系统中,我们可以使用`jps`命令...
JVM 的运行机制 多线程 JVM 的内存区域 JVM 会创建操作系统的接口创建一个原生线程。JVM 线程和操作系统线程是一一对应的
每当方法执行时,JVM就会在栈中创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。 - **方法区(Method Area)**:用于存储已被虚拟机加载的类信息、常量、静态变量等数据。...
《HotSpot线程实现——线程创建》 在Java编程中,线程是我们处理并发和多任务的基础。本文将深入探讨HotSpot虚拟机中线程的实现,主要关注线程的创建过程。我们使用的JDK版本为1.7。请注意,本文不会涉及Java线程的...
在Java Web开发中,性能优化是一项至关重要的任务,特别是对于JVM(Java虚拟机)的管理,包括线程和内存的高效使用。当系统出现性能瓶颈或者内存泄漏时,了解如何排查和解决这些问题显得尤为关键。本文将详细介绍...
而每个线程创建时JVM都会为其创建工作内存 工作内存是每个线程的私有数据区域 而JAVA内存模型规定所有变量都存储在主内存 主内存是共享内存区域 所有线程都可以访问 但线程对变量的操作必须在工作内存中进行 ...
jvm支持的最大线程数有一定的限制,包括32位Linux系统可创建的最大pid数(32678)和系统最大可创建的线程数量(/proc/sys/kernel/threads-max)。这些限制可以通过修改系统参数来改变。 6. 应用场景 jvm支持的最大...
通过调整JVM参数,我们可以控制堆大小、垃圾收集策略、线程栈大小等,以达到最佳的运行效果。例如,通过-Xms和-Xmx设置堆内存大小,-XX:+UseG1GC选择垃圾收集器等。 总结来说,JVM是Java编程的重要组成部分,它的...
- JVM指令是字节码,每条指令对应一个特定的操作,如加载和存储变量、算术运算、控制流程、对象创建和方法调用等。 - 指令手册会列出所有这些指令,比如`iconst_5`表示将整数5压入操作数栈,`aload_0`用于将局部...
2. **守护线程**:守护线程通常由JVM自动创建,用于在后台执行任务,例如垃圾回收(GC)就是典型的守护线程。它们的主要职责是为用户线程提供服务,且不阻止JVM的关闭。当JVM中没有非守护线程在运行时,即使守护线程...
例如,“iload”表示加载整数到操作数栈,“anewarray”用于创建数组对象,“iand”表示执行整数位与操作等。这些指令构成了 JVM 执行 Java 字节码的基础。 ##### 2.2 JVM 的 CPU 架构 JVM 的 CPU 架构是其指令...
在这个"Jvm.rar_jni_jni线程_jvm"的压缩包中,我们主要探讨的是JNI与Java线程的交互。 首先,JNI的核心是定义了一套接口,让Java代码可以创建本地方法(Native Method),这些方法可以在C/C++中实现。在"Jvm.cpp"这...
- **内存回收**:JVM需要自动管理内存,包括对象的创建和回收。 - **内存分析**:通过分析JVM内存使用情况,可以优化程序性能,避免如Full GC频繁发生等性能问题。 #### 8. 垃圾收集与收集器 - **垃圾收集**:指JVM...
- **JVM栈(JVM Stack)**:线程私有,每个线程创建时都会创建对应的JVM栈。栈中存储局部变量(包括基本类型和对象引用)、方法参数、Stack Frame。当变量超出作用域,JVM会自动释放栈内存。栈内存分配快速,但大小...