zoukankan      html  css  js  c++  java
  • 关于Java线程的实现


    在操作系统中,有两种不同的方法提供线程支持:用户层的用户线程,或内核层的内核线程。

    其中用户线程在内核之上支持,并在用户层通过线程库来实现。不需要用户态/核心态切换,速度快。操作系统内核不知道多线程的存在,因此一个线程阻塞将使得整个进程(包括它的所有线程)阻塞。由于这里的处理器时间片分配是以进程为基本单位,所以每个线程执行的时间相对减少。

    内核线程由操作系统直接支持。由操作系统内核创建、调度和管理。内核维护进程及线程的上下文信息以及线程切换。一个内核线程由于I/O操作而阻塞,不会影响其它线程的运行。

    Java线程的实现是怎样的呢?我们通过SUN Java 6的源码了解其在Windows和Linux下的实现。

    在Windows下的实现,os_win32.cpp中
    // Allocate and initialize a new OSThread
    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, truefalse, 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下的实现是使用内核线程。

    而在Linux下又是怎样的呢?

    在os_linux.cpp文件中的代码摘录如下:

    # include <pthread.h>

    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下是使用用户线程实现的。



  • 相关阅读:
    微信开发返回验证来源方式代码
    Yii 开发过程 tips
    PHP 搜索分词实现代码
    PHP 中文字符串截取
    Ubuntu16.04设置静态ip
    Linux(Ubuntu18.04)安装Chrome浏览器
    ubuntu18.04安装redis
    ubuntu18.04虚拟机安装docker
    虚拟机安装ssh,关闭防火墙
    面试送命题,你为什么从上家公司离职?(面试题总结大全)
  • 原文地址:https://www.cnblogs.com/jobs/p/717583.html
Copyright © 2011-2022 走看看