首页 > 编程语言 > 详细

Java中的线程是如何与Linux进行调用的

时间:2020-04-26 11:00:05      阅读:58      评论:0      收藏:0      [点我收藏+]

  在Java基础中我们知道,一般要实现一个线程通常是有两种方法,当然我这里没有算上使用callable等其他的实现方式。这里我们暂且使用继承Thread或者实现runnable接口。那么我们总是需要重写里面的run方法。

 public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group‘s list of threads
         * and the group‘s unstarted count can be decremented. */
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

    private native void start0();

可以从上面的源码可以看见,实际上thread在调用start方法时,其实还调用了一个start0的方法。而且这个start0的方法是个本地native方法。我们可以假设其实Java虚拟机就是调用这个start0的方法,开启了一个Linux的内核线程。下面我们来做些实验:

我们简单的写一个Java类TestThread:

package test;

public class TestThread{
        static{
              System.loadLibrary("TestThreadNative");
        }
        public static void main(String[] args){
                TestThread testThread=new TestThread();
                testThread.start0();
        }
        private native void start0();
}

这里我么来说说,这里的System.loadLibrary方法,这个方法就类似我们win电脑中dll,一个链接库。其实这个库就是就是为了完成下面start0函数的实现。而且这里要注意一点,这串字符确定后,需要在编译这个库时需要指定,所以请记住各个字符串。

接下来我们使用Javac函数来编译一下:就可以得到TestThread.class文件

下一步,我们使用Javah TestThread.class  注意使用这个命令是需要带类的全路径包名,否则会报错。我这里是 javah test.TestThread 。得到就是一个test_TestThread.h 通常这个文件是在和Java文件包的同一级目录下。我们最好把这个test_TestThread.h放进和TestThread.class一起。下面是生成的test_TestThread.h的内容:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class test_TestThread */

#ifndef _Included_test_TestThread
#define _Included_test_TestThread
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     test_TestThread
 * Method:    start0
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_test_TestThread_start0
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

我们从上面可以看出,其实我们需要实现的就是其中的这个方法

       JNIEXPORT void JNICALL Java_test_TestThread_start(JNIEnv *, jobject);

那么下一步,我们此时已经得到了TestThread.class、test_TestThread.h 我们接下来需要写一个C文件thread.c,这个C文件引入testThread.h这个头文件,在thread.c文件中,我们实现那个头文件中的start线程方法。在Linux中,创建一个线程需要用到pthread_create(&pid,NULL,thread_entity,NULL);这个方法。  

  这里解释下,第一个参数pid是线程的地址,第二个参数是线程属性,第三个参数方法是线程体,或者说是实现线程逻辑的函数指针,第四个参数是传入的参数;

     下面贴出我们自己定义的thread.c的内容:

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include "test_TestThread.h"
pthread_t pid;
void* thread_entity(void* arg)
{
      while(1){
           usleep(100);
           printf("i am new thread\n");
      }
}
JNIEXPORT void JNICALL Java_test_TestThread_start0(JNIEnv  *env, jobject c1)
{
     pthread_create(&pid,NULL,thread_entity,NULL);
     while(1){
           usleep(100);
           printf("i am main\n");
     }
}
int main()
{
   return 0;
}

最后,我们需要把这部分逻辑,编译成在TestThread.java中的TestThreadNative.so文件 然后让TestThread.java文件进行加载。

gcc -fPIC -I /usr/lib/jvm/java-1.8.0-openjdk-amd64/include/ -I /usr/lib/jvm/java-1.8.0-openjdk-amd64/include/linux/ -shared -o libTestThreadNative.so thread.c
/usr/lib/jvm/java‐1.8.0‐openjdk/include   //这个文件下有jni相关的文件  因为我们在test_TestThread.h中引入了 #include <jni.h>
/usr/lib/jvm/java‐1.8.0‐openjdk/include/linux   //在这个文件下 我们需要linux相关的依赖把  这里我还不是特别清楚 可以在这个打个问号?
注意:在输入这个命令的时候很容易出错 出错的原因很可能是 链接的文件路径不正确 所以一定要确定位置正确 最好输入的时候按TAB键 这样可以保证路径正确

现在离最后一步还差:把链接库加入到环境变量:

 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/root/test   //注意 我这里是用root账号登录的 所以是/root/test 通常是/home/用户名/test

最后运行 Java  com.TestThread 带包名运行即可

 技术分享图片

到这里我们就完成了Java调用C语言的的线程的过程。

总结:TestThread.java ->TestThread.class->test_TestThread.h->thread.c->libTestThreadNative.so->添加so文件到libaray_path最后运行 java test.TestThread

Java中的线程是如何与Linux进行调用的

原文:https://www.cnblogs.com/foot-or-car/p/12776555.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!