代码改变世界

JVM的线程实现机制

2012-08-10 14:12  康杜  阅读(2812)  评论(1编辑  收藏  举报

最近我在看<Advanced Programming on UNIX Environment 2nd Edition>(以下简称APUE), 读到线程这一章节。上面讲到OS提供多线程环境,比如创建线程、销毁线程以及线程的同步控制。我突然想到,”JVM的线程管理是不是调用了OS的线程管理呢?“ 针对这个问题,我做了一些研究。这篇文章是这些研究的总结。由于水平有限(我现在还没有能力读懂JVM的源代码),所以无法提供代码例证,如果文章中出现任何问题和纰漏,请不吝指教。

线程运行方式

在单处理器的系统中,多线程是按时间片方式运行的;在多处理器(或者多核)的系统中,多个线程可以同时运行。

”On a single processor, multithreading generally occurs by time-division multiplexing; the processor switches between different threads. On a multiprocessor (including multi-core system), the threads or tasks will actually run at the same time.

--http://en.wikipedia.org/wiki/Thread_(computer_science)

所以从系统的吞吐量方面来说,多线程是非常重要的。而且即使是单处理器(单核的),多线程依然能够提供提升系统吞吐量的好处,比如某个线程执行的任务受到阻塞,其他的线程依然能够继续运行。

线程模型

  • 内核级别线程

    内核级别线程(Kernel-level threading)是指用户进程通过内核提供API创建的线程。这样用户进程里的线程和内核调度的线程是1:1对应的。这也就最简单的线程管理方法。

  • 用户级别线程

     用户基本线程(User-level threading)是指 用户进程自己实现线程机制。在这种情况下,内核是不知道有多少线程存在的,同时线程上下文切换更快,而且在不支持多线程的操作系统上也能实现多线程。但是,用户级别的线程也带来相当大的坏处,比如不能充分利用多处理器(多核)系统;如果进程中的一个线程执行阻塞的I/O请求,那么整个用户进程都会被阻塞。

  • 混合线程

     混合线程是内核级别线程和用户级别线程的混合体,提供了以上两种模型的优点,但是带来很大的复杂性。

 

绿色进程

首先看绿色进程的定义:

绿色线程是指有虚拟机调度的线程,而不是通过内核调度的。所以绿色进程是用户级别的进程。

”In computer programming, green threads are threads that are scheduled by a virtual machine (VM) instead of natively by the underlying operating system.

http://en.wikipedia.org/wiki/Green_threads"

前面也讲过用户级别线程在I/O或者利用多核处理器方面性能不如内核级别的线程。所以,在Java 1.1以后,JVM就从绿色线程机制转为内核级别线程机制。

 

由于是内核级别的线程机制,所以JVM的线程数量受到内核参数的影响
 
通常来说,这个参数是运行时的参数,是内核根据进程的栈空间容量计算出来的。
cat /proc/sys/kernel/thread-max
 
修改这个参数值
echo 1000 > /proc/sys/kernel/threads-max
 
运行这个程序
 
/*
 * Copyright (c) 2011.  Peter Lawrey
 *
 * "THE BEER-WARE LICENSE" (Revision 128)
 * As long as you retain this notice you can do whatever you want with this stuff.
 * If we meet some day, and you think this stuff is worth it, you can buy me a beer in return
 * There is no warranty.
 */

package com.google.code.java.core.threads;

import java.util.ArrayList;
import java.util.List;

public class MaxThreadsMain {

  public static final int BATCH_SIZE = 4000;

  public static void main(String... args) throws InterruptedException {
    List<Thread> threads = new ArrayList<Thread>();
    try {
      for (int i = 0; i <= 100 * 1000; i += BATCH_SIZE) {
        long start = System.currentTimeMillis();
        addThread(threads, BATCH_SIZE);
        long end = System.currentTimeMillis();
        Thread.sleep(1000);
        long delay = end - start;
        System.out.printf("%,d threads: Time to create %,d threads was %.3f seconds %n", threads.size(), BATCH_SIZE, delay / 1e3);
      }
    } catch (Throwable e) {
      System.err.printf("After creating %,d threads, ", threads.size());
      e.printStackTrace();
    }

  }

  private static void addThread(List<Thread> threads, int num) {
    for (int i = 0; i < num; i++) {
      Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
          try {
            while (!Thread.interrupted()) {
              Thread.sleep(1000);
            }
          } catch (InterruptedException ignored) {
            //
          }
        }
      });
      t.setDaemon(true);
      t.setPriority(Thread.MIN_PRIORITY);
      threads.add(t);
      t.start();
    }
  }
}

 


alex@ubuntu:~/download/core-java-performance-examples-read-only/src/test/java$ java com.google.code.java.core.threads.MaxThreadsMain 4,000 threads: Time to create 4,000 threads was 1.923 seconds 8,000 threads: Time to create 4,000 threads was 4.465seconds
echo 1000 > /proc/sys/kernel/threads-max
alex@ubuntu:~/download/core-java-performance-examples-read-only/src/test/java$ java com.google.code.java.core.threads.MaxThreadsMain
After creating 604 threads, java.lang.OutOfMemoryError: unable to create new native thread at java.lang.Thread.start0(Native Method) at java.lang.Thread.start(Thread.java:657) at com.google.code.java.core.threads.MaxThreadsMain.addThread(MaxThreadsMain.java:54) at com.google.code.java.core.threads.MaxThreadsMain.main(MaxThreadsMain.java:24)

 可以看出,在没有设定线程最大数1000之前, 以上Java程序可以创建到8000个线程(我中途中断了)。然后,我重新启动机器,执行 echo 1000 > /proc/sys/kernel/threads-max

然后运行Java程序,出现了创建进程错误的提示。(但是,我想提示信息不正确,应该是线程数超过最大线程数才准确。)