美文网首页并发
java线程模型

java线程模型

作者: love111 | 来源:发表于2019-11-19 22:32 被阅读0次

Thread的start()方法

示例代码
package com.thread;
public class ThreadTest {
![pthread_create.png](https://img.haomeiwen.com/i7310356/b1e7bf980513efef.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    public static void main(String[] args) {
        Thread thread = new Thread( () -> System.out.println("thread run......") );
        thread.start();
    }
}
调用过程

start()方法调用


start.png

start0()本地方法


start0.png
调用本地方法如何调用到操作系统
通过native本地方法会首先经过C语言代码进行方法映射再调用hostpot虚拟机生成一个虚拟机类最后调用操作系统函数,最终会创建一个线程pthread_create

为什么不直接调用操作系统
java虚拟机(C/C++)创建一个对象javaThread,与java代码对象一一对应。多个中间层可控
JDK包中提供的java库、(C文件)调用操作系统函数、(C++)调用虚拟机的代码。hostpod虚拟机(win版本通过java.exe运行)
(java start thread对应操作系统通过 pthread_creat创建。java sync 就是os thread锁的原理)
thread.c


threadc.png
jvm.cpp
jvmcpp.png
os_linux.cpp
pthread_create.png
对于Thread线程类 start()方法是要调用操作系统方法pthread_create,我们不能写自己的逻辑。所以会由操作系统回调到run方法通过pthread_create创建线程传一个java_start方法(run方法是pthread_create第三个参数)
java_start.png

JNI调用过程测试

示例代码
public class MyThread {
    static {
        System.loadLibrary( "MyThreadNative" );
    }
    public static void main(String[] args) {
        MyThread thread = new MyThread( );
        thread.start0();
    }
    public void run(){
        System.out.println("jni MyThread run method");
    }
    private native void start0();
}
编译成class文件

MyThread.java编译成MyThread.class文件(javac MyThread.java)


javac.png
生成.h头文件

MyThread.class生成MyThread.h文件(javah MyThread)


javah.png

Mythread.h


Mythreadh.png
编写C文件

thread.c 需要include引用生成的MyThread.h文件,在MyThread.h文件中,生成的Java_MyThread_start0方法需要在这里使用、参数类型、返回结果也需要相同。这段代码测试的意义在于调用操作系统(Linux)函数pthread_create(&pid,NULL,thread_entity,NULL);函数会调用到第三个参数的thread_entity()方法的调用。测试结果出现I am thread_entity和i am main打印,说明完成了MyThread 类的start()方法的JNI调用

#include <pthread.h>
#include <stdio.h>
#include "MyThread.h"

pthread_t pid;

void* thread_entity(void* arg)
{
while(1){
  printf("I am thread_entity\n");
  }
}

JNIEXPORT void JNICALL Java_MyThread_start0(JNIEnv *env, jobject c1)
{
  pthread_create(&pid,NULL,thread_entity,NULL);
  while(1){
    printf("i am main \n");
  }
}

int main(){
  return 0;
}
生成so文件

thread.c文件生成so文件(lib***.so形式,中间是System.loadLibrary( "MyThreadNative" );所引用的)
gcc thread.c -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux" -fPIC -shared -o libMyThreadNative.so

.so文件加入到path

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:{libMyThreadNative.so}所在的路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/thread

运行

运行MyThread类(java MyThread)


javaMyThread.png

回调run()方法测试

JNI反射回调MyThread类的run()方法
由于上面示例代码MyThread.class类中已经包含run()方法,所以生成的MyThread.h文件可以使用。只需要重新编写thread.c文件调用run()方法就可以了

thread.c

#include <pthread.h>
#include <stdio.h>
#include "MyThread.h"
JNIEXPORT void JNICALL Java_MyThread_start0(JNIEnv *env, jobject cl){
    jclass cls;
    jobject obj;
    jmethodID cid;
    jmethodID rid;
    jint ret = 0;
    cls = (*env)->FindClass(env, "MyThread");
    if(cls == NULL){
        printf("FindClass null");
        return;
    }
    cid = (*env)->GetMethodID(env, cls, "<init>", "()V");
    if(cid == NULL){
       printf("constructor null");
       return;
    }   
    obj = (*env)->NewObject(env, cls, cid);
    if(obj == NULL){
       printf("NewObject null");
       return;
    }
    rid = (*env)->GetMethodID(env, cls, "run", "()V");  
    ret = (*env)->CallIntMethod(env, obj, rid, NULL);   
    printf("finsh call method\n");       
} 
int main(){
    return 0; 
}

参数解释:
1、JNIEnv:相当于虚拟机环境
2、jclass : c得到的java类
3、jobject :c得到的java对象
4、cid :c得到的java类的构造方法
5、rid :c得到的java类的run方法
FindClass()、GetMethodID()、CallIntMethod()都是C语言的方法

thread.c文件生成so文件

首先有JAVA_HOME环境,可以使用全路径
gcc thread.c -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux" -fPIC -shared -o libMyThreadNative.so

导入路径

export LD_LIBRARY_PATH=LD_LIBRARY_PATH:so文件所在的路径 如:/root/thread/libMyThreadNative.so export LD_LIBRARY_PATH=LD_LIBRARY_PATH:/root/thread/

执行java程序

java Mythread


jnirun.png

pthread_create线程控制原语

man pthread_create (linux通过man获取)

NAME
       pthread_create - create a new thread

SYNOPSIS
       #include <pthread.h>

       int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                          void *(*start_routine) (void *), void *arg);

       Compile and link with -pthread.

DESCRIPTION
       The  pthread_create()  function starts a new thread in the calling process.  The new thread starts execution by invoking start_routine(); arg is passed as the sole argu‐
       ment of start_routine().

       The new thread terminates in one of the following ways:

       * It calls pthread_exit(3), specifying an exit status value that is available to another thread in the same process that calls pthread_join(3).

       * It returns from start_routine().  This is equivalent to calling pthread_exit(3) with the value supplied in the return statement.

       * It is canceled (see pthread_cancel(3)).

       * Any of the threads in the process calls exit(3), or the main thread performs a return from main().  This causes the termination of all threads in the process.

       The attr argument points to a pthread_attr_t structure whose contents are used at thread creation time to determine attributes for the new thread; this structure is ini‐
       tialized using pthread_attr_init(3) and related functions.  If attr is NULL, then the thread is created with default attributes.

       Before  returning,  a  successful  call  to  pthread_create() stores the ID of the new thread in the buffer pointed to by thread; this identifier is used to refer to the
       thread in subsequent calls to other pthreads functions.

       The new thread inherits a copy of the creating thread's signal mask (pthread_sigmask(3)).  The set of pending signals for the new thread is empty  (sigpending(2)).   The
       new thread does not inherit the creating thread's alternate signal stack (sigaltstack(2)).

       The new thread inherits the calling thread's floating-point environment (fenv(3)).

       The initial value of the new thread's CPU-time clock is 0 (see pthread_getcpuclockid(3)).

   Linux-specific details
       The new thread inherits copies of the calling thread's capability sets (see capabilities(7)) and CPU affinity mask (see sched_setaffinity(2)).

RETURN VALUE
       On success, pthread_create() returns 0; on error, it returns an error number, and the contents of *thread are undefined.

ERRORS
       EAGAIN Insufficient resources to create another thread.

       EAGAIN A  system-imposed  limit on the number of threads was encountered.  There are a number of limits that may trigger this error: the RLIMIT_NPROC soft resource limit
              (set via setrlimit(2)), which limits the number of processes and threads for a real user ID, was reached; the kernel's system-wide limit on  the  number  of  pro‐
              cesses and threads, /proc/sys/kernel/threads-max, was reached (see proc(5)); or the maximum number of PIDs, /proc/sys/kernel/pid_max, was reached (see proc(5)).

       EINVAL Invalid settings in attr.

       EPERM  No permission to set the scheduling policy and parameters specified in attr.

ATTRIBUTES
       For an explanation of the terms used in this section, see attributes(7).

       ┌─────────────────┬───────────────┬─────────┐
       │Interface        │ Attribute     │ Value   │
       ├─────────────────┼───────────────┼─────────┤
       │pthread_create() │ Thread safety │ MT-Safe │
       └─────────────────┴───────────────┴─────────┘

CONFORMING TO
       POSIX.1-2001, POSIX.1-2008.

NOTES
       See  pthread_self(3)  for further information on the thread ID returned in *thread by pthread_create().  Unless real-time scheduling policies are being employed, after a
       call to pthread_create(), it is indeterminate which thread—the caller or the new thread—will next execute.

       A thread may either be joinable or detached.  If a thread is joinable, then another thread can call pthread_join(3) to wait for the thread to  terminate  and  fetch  its
       exit  status.   Only when a terminated joinable thread has been joined are the last of its resources released back to the system.  When a detached thread terminates, its
       resources are automatically released back to the system: it is not possible to join with the thread in order to obtain its exit status.  Making a thread detached is use‐
       ful for some types of daemon threads whose exit status the application does not need to care about.  By default, a new thread is created in a joinable state, unless attr
       was set to create the thread in a detached state (using pthread_attr_setdetachstate(3)).

       On Linux/x86-32, the default stack size for a new thread is 2 megabytes.  Under the NPTL threading implementation, if the RLIMIT_STACK soft resource limit  at  the  time
       the  program  started has any value other than "unlimited", then it determines the default stack size of new threads.  Using pthread_attr_setstacksize(3), the stack size
       attribute can be explicitly set in the attr argument used to create a thread, in order to obtain a stack size other than the default.

BUGS
       In the obsolete LinuxThreads implementation, each of the threads in a process has a different process ID.  This is in violation of the POSIX threads  specification,  and
       is the source of many other nonconformances to the standard; see pthreads(7).

函数参数意义:
pthread_t *thread 传出参数,调用之后会传出被创建的线程id 定义 pthread_t pid; 取地址 &pid
const pthread_attr_t *attr 线程属性,在测试pthread_create函数的时传NULL,保持默认属性
void (start_routine) (void *) 线程启动后的主体函数,相当于java中的run
void *arg 主体函数参数,没有可以传NULL

总结:

java对象调用native本地方法会首先经过C语言代码进行方法映射再调用hostpot虚拟机生成一个虚拟机类最后调用操作系统函数,例如:Thread类的start()方法会调用操作系统函数pthread_create创建一个线程(不是跟模拟的一样通过JNI调用,是通过C++技术调用的thread->run();)。其他native方法也是类似的过程。

相关文章

  • Reactor线程模型及其在Netty中的应用

    什么是Reactor线程模型 Java中线程模型大致可以分为: 单线程模型 多线程模型 线程池模型(executo...

  • 线程池

    线程是调度CPU资源的最小单位,线程模型分为KLT模型和ULT模型,Java采用的是KLT模型,java线程与OS...

  • Java线程模型

    Java线程模型 本文将从线程类型、线程通信、线程调度三个方面分析Java中的线程模型。 什么是线程? 线程就是进...

  • 并发编程有关知识点(五)

    Java 内存模型 java线程安全总结 深入理解java内存模型系列文章 线程状态: 一张图让你看懂JAVA线程...

  • 第12章 Java内存模型与线程

    第12章 Java内存模型与线程 12.3Java内存模型 Java内存模型 [1](Java Memory Mo...

  • 深入理解Java并发内存模型

    Java内存模型是什么 Java 内存模型翻译自Java Memory Model,也称Java多线程内存模型,简...

  • java多线程(六)---Java内存模型

    1 Java内存模型(JMM) Java线程间的通信由Java内存模型(JMM)控制,JMM决定一个线程对共享变量...

  • Java内存模型&Volatile

    1.Java内存模型 1.1 Java内存模型(JMM) Java线程间的通信由Java内存模型(JMM)控制,J...

  • java内存模型

    引用: Java内存模型 java内存模型线程栈:本地变量,堆:对象,对象成员变量,静态成员变量 如果两个线程同时...

  • java内存模型

    前言 在学习java多线程并发编程前,必须要了解java内存模型,只有了解java内存模型,才能知道为什么多线程并...

网友评论

    本文标题:java线程模型

    本文链接:https://www.haomeiwen.com/subject/yilgictx.html