Java线程的本质

序言

模拟一个线程

我们知道,java为我们提供了Thread线程类操作线程,那么我们如何不使用Thread实现线程呢?我们可以手动去调用操作系统的线程方法,操作流程图如下:

Created with Raphaël 2.2.0 ThreadTest.java#start1() CThreadTest.c#start1() 操作系统的pthread_create()
  • com.cbl.thread.ThreadTest.java
public class ThreadTest {

    // java使用jni调用native方法,lib名为libCThreadTestNative.so去掉lib前缀,lib由CThreadTest.c在以下步骤生成
    static {
        System.loadLibrary("CThreadTestNative");
    }

    public native void start1();

    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
        threadTest.start1();
    }
}
  • 编译ThreadTest.java得到com_cbl_thread_ThreadTest.h
javac -h . ThreadTest.java
  • com.cbl.thread.CThreadTest.c
// 该类的核心是pthread_create方法,该方法传递一个回调方法,可以把这个回调方法看作是线程的执行逻辑,类似run方法
#include <pthread.h>
#include <stdio.h>
#include "com_cbl_thread_ThreadTest.h" // 该文件由ThreadTest.java编译过来

pthread_t pid;

// 该方法为回调方法,类似于java启动线程后去执行run方法。
void* thread_entity(void* args) {
    while (1) {
        usleep(100);
        printf("开启线程");
    }
}

// 查看com_cbl_thread_ThreadTest.h并把JNIEXPORT方法体复制到这里
JNIEXPORT void JNICALL Java_com_cbl_thread_ThreadTest_start1(JNIEnv *env, jobject c1) {
    pthread_create(&pid, NULL, thread_entity, NULL);
    while (1) {
        usleep(1000);
        printf("main\n");
    }
}

int main() {
    return 0;
}
  • 编译CThreadTest.c得到.so文件
gcc -fPIC -I /home/cbl/develop/jdk/jdk1.8.0_251/include -I /home/cbl/develop/jdk/jdk1.8.0_251/include/linux -shared -o libCThreadTestNative.so CThreadTest.c
  • 把libCThreadTestNative.so文件放到linux库
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/cbl/proj/threadTest/com/cbl/thread/libCThreadTestNative.so
  • 执行ThreadTest.class,最终结果是主线程和子线程交替打印。
java -classpath /home/cbl/proj/threadTest com.cbl.thread.ThreadTest
Java线程的本质

当我们不用Thread类去启动线程时,我们应该都可以猜到,Thread.start()方法其实调用了操作系统的p_thread_create()方法,run方法又作为p_thread_create()的回调方法,所以能够被执行到。

查看start方法源码,是一个本地方法,是不是跟我们上面的start1()很像?

private native void start0();

调试JDK源码

这里我们尝试去编译openjdk9,需要jdk8环境的支持,即官网所说的boot jdk,openjdk9的源码可以在gitee下载。编译成功后可以看到build/linux-x86_64-normal-server-release目录。

配置jdk8环境
  • sudo vim /etc/profile
JAVA_HOME=/home/cbl/develop/jdk/jdk1.8.0_251
PATH=$JAVA_HOME/bin:$PATH
CLASSPATH=$JAVA_HOME/jre/lib/ext:$JAVA_HOME/lib/tools.jar
export PATH JAVA_HOME CLASSPATH
source /etc/profile
编译openjdk9

需要上一个版本的环境,官网说的Boot JDK即jdk1.8。gitee下载openjdk9的源码,解压进入openjdk9目录,执行。

为什么不用openjdk11+呢,因为执行make images时踩过坑,找不到jre/lib/ext目录

bash configure

按照提示安装缺失的依赖

sudo yum -y groupinstall "Development Tools"
sudo yum  -y install libXtst-devel libXt-devel libXrender-devel libXrandr-devel libXi-devel
sudo yum  -y install cups-devel
sudo yum  -y install fontconfig-devel
sudo yum  -y install alsa-lib-devel
sudo yum  -y install elfutils-libelf-devel
make images

遇到了class JdiDefaultExecutionControl is public, should be declared in a file named JdiDefaultExecutionControl.java错误,只需要把java源文件名的JDI改成Jdi即可,算是jdk9的bug?

编译完成后,使用以下命令验证

./build/*/images/jdk/bin/java -version

测试(好像报错了)

make run-test-tier1
linux安装clion

官网下载clion的linux包,解压

  • 安装cmake
wget "https://cmake.org/files/v3.19/cmake-3.19.0-rc1.tar.gz"
cd cmake-3.10.0-rc3/
./bootstrap
gmake
gmake install
  • 启动(需要配置xming),然后系统自动打开xming,即可看到图形界面了
./home/cbl/develop/clion/bin/clion.sh

使用Clion打开jdk9目录,设置run configuration

–> cmake application

–> executable:build/linux-x86_64-normal-server-release/jdk/bin/java

–> program arguments:-version

开始调试java的start方法

创建一个简单的thread类,javac xxx.java编译,然后放到clion的jdk12目录下jdk12/build/linux-x86_64-server-slowdebug/jdk/bin替换com文件夹,修改run configuration,program arguments改为com.xxx.xxx.Xxx

找到os_linux.cpp#pthread_attr_setguardsize方法,打断点

jvm.cpp#JVM_ENTRY

​ JVM_StartThread

Created with Raphaël 2.2.0 java start() Thread.c start0() JVM实例化一个C++对象JavaThread 操作系统的pthread_create()

其他资料

vmware设置固定ip
  • 设置NAT网络

  • 修改虚拟网络编辑器:

    编辑->虚拟网络编辑器->VMnet8->子网IP:192.168.118.0 子网掩码->255.255.255.0
    NAT设置->网关IP:192.168.118.2

  • 修改ifcfg-ens33

sudo vim /etc/sysconfig/network-scripts/ifcfg-ens33
BOOTPROTO=static
IPADDR=192.168.118.10
NETMASK=255.255.255.0
GATEWAY=192.168.118.2
DNS1=114.114.114.114
ONBOOT=yes
  • 重启网络
service network restart
centos安装图形界面
yum groupinstall "GNOME Desktop" "Graphical Administration Tools"
# 下面几个命令其实我不怎么用,都是使用xming运行图形界面的
systemctl set-default multi-user.target
systemctl set-default graphical.target
startx
xming+xshell打开命令行
  • 安装xming,启动xlaunch,一路next
  • 打开xshell会话->属性->SSH->隧道->X DISPLAY,改成localhost:0.0
  • 修改xming目录下的X0.hosts,加上centos的ip
  • 进入xshell,执行
export DISPLAY=192.168.118.10:0.0
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值