Java线程本质
java当中的线程和操作系统的线程是什么关系?
关于操作系统的线程 linux操作系统的线程控制原语
int pthread create(pthread t *thread, const pthread attr t *attr,
void *(*start_routine) (void *), void *arg);
可以在linux系统下面通过man手册查看该函数的定义

根据man配置的信息可以得出pthread_create会创建一个线程,这个函数是linux系统的函数,可以用C或者C++直接调用,上面信息也告诉程序员这个函数在pthread.h,这个函数有四个参数
|
参数名字 |
参数定义 |
参数解释 |
|
pthread_t *thread |
传出参数,调用之后会传出被创建 线程的id |
定义 pthread_t pid;继而取地址 &pid |
|
const pthread_attr_t *attr |
线程属性,关于线程属性是linux 的知识 |
一般传NULL,保持默认属性 |
|
void (start_routine) (void *) |
线程的启动后的主体函数 |
需要你定义一个函数,然后传函 数名即可 |
|
void *arg |
主体函数的参数 |
没有可以传nulll |
linux上启动一个线程的代码:
//头文件
#include <pthread.h>
#include <stdio.h>
//定义一个变量,接受创建线程后的线程id
pthread_t pid;
//定义线程的主体函数
void* thread entity(void* arg) {
printf("i am new Thread! from c");
}
//main方法,程序入口,main和java的main一样会产生一个进程,继而产生一个main线程
int main() {
//调用操作系统的函数创建线程,注意四个参数
pthread create(&pid,NULL,thread entity,NULL);
//usleep是睡眠的意思,那么这里的睡眠是让谁睡眠呢?
//为什么需要睡眠?如果不睡眠会出现什么情况
usleep();
printf("main\n");
}
假设有了上面知识的铺垫,那么可以试想一下java的线程模型到底是什么情况呢?
在java代码里启动一个线程的代码
public class Example4Start {
public static void main(String[] args) {
Thread thread = new Thread(){
@Override
public void run() {
System.out.println("i am new Thread! from java ");
}
};
thread.start();
}
}
这里启动的线程和上面我们通过linux的pthread_create函数启动的线程有什么关系呢?只能去可以查看start()的源码了,看看java的start()到底干了什么事才能对比出来。start方法的源码的部分截图

可以看到这个方法最核心的就是调用了一个start0方法,而start0方法又是一个native方法,故而如果要搞明白start0我们需要查看Hotspot的源码,好吧那我们就来看一下Hotspot的源码吧,Hotspot的源码怎么看么?一般直接看openjdk的源码,openjdk的源码如何查看、编译调试?openjdk的编译我们后面会讨论,在没有openjdk的情况下,我们做一个大胆的猜测,java级别的线程其实就是操作系统级别的线程,什么意思呢?说白了我们大胆猜想 star----->start0------------>ptherad_create
我们鉴于这个猜想来模拟实现一下java启动线程
public class EnjoyThread {
public static void main(String[] args) {
//自己定义的一个类
EnjoyThread enjoythread =new EnjoyThread();
enjoythread.start0();
}
//本地方法
private native void start0();
}
这里我们让自己写的start0调用一个本地方法,在本地方法里面去启动一个系统线程,好吧我们写一个c程序来启动本地线程
本地方法的代码编写
#include <pthread.h>
#include <stdio.h>
//定义变量接受线程id
pthread t pid;
//线程的主体方法相当于 java当中的run
void* thread entity(void* arg) {
//子线程死循环
while(){
//睡眠100毫秒
usleep();
//打印
printf("I am new Thread\n");
}
}
//c语言的主方法入口方法,相当于java的main
int main() {
//调用linux的系统的函数创建一个线程
pthread create(&pid,NULL,thread entity,NULL);
//主线程死循环
while(){
//睡眠100毫秒
usleep();
//打印
printf("I am main\n");
}
}
在linux上编译、运行上述C程序
编译这个程序
gcc thread.c -o thread.out -pthread
运行这个程序
./thread.out
结果如图所示

结果是两个线程一直在交替执行,得到我们预期的结果。现在的问题就是我们如何通过start0调用这个c程序,这里就要用到JNI了
java利用JNI调用本地方法
package com.enjoy.concurrency;
public class EnjoyThread {
//装载库,保证JVM在启动的时候就会装载,故而一般是也给static
static {
System.loadLibrary( "EnjoyThreadNative" );
}
public static void main(String[] args) {
EnjoyThread enjoyThread =new EnjoyThread();
enjoyThread.start0();
}
private native void start0();
}
这样完全还原java当中调用JVM源码启动线程的场景,继而可以系统的了解java线程的模型和本质
Java线程本质的更多相关文章
- 面试官:都说阻塞 I/O 模型将会使线程休眠,为什么 Java 线程状态却是 RUNNABLE?
摘要: 原创出处 https://studyidea.cn 「公众号:程序通事 」欢迎关注和转载,保留摘要,谢谢! 使用 Java 阻塞 I/O 模型读取数据,将会导致线程阻塞,线程将会进入休眠,从而 ...
- Java 线程安全问题的本质
原创声明:作者:Arnold.zhao 博客园地址:https://www.cnblogs.com/zh94 目录: 线程安全问题的本质 理解CPU JVM虚拟机类比于操作系统 重排序 汇总 一些解释 ...
- java线程 - 多线程 - 守护线程
1.多线程执行者/处理类 都是Runnable的实现类(如自定义类实现Runnable 或 java原生的Thread.FutureTask),但最后都必须封装成Thread线程类由Thread.st ...
- java线程(2016-4-7)
Thread.yield()的调用是对线程调度器(Java线程机制的一部分,可以将CPU从一个线程转移到另一个线程)的一种建议,它在声明:"我已经执行完生命周期中最重要的部分了,此刻正是切换 ...
- java线程内存模型,线程、工作内存、主内存
转自:http://rainyear.iteye.com/blog/1734311 java线程内存模型 线程.工作内存.主内存三者之间的交互关系图: key edeas 所有线程共享主内存 每个线程 ...
- java线程详解(三)
java线程间通信 首先看一段代码 class Res { String name; String sex; } class Input implements Runnable { private R ...
- Java线程与Linux内核线程的映射关系[转]
Linux从内核2.6开始使用NPTL (Native POSIX Thread Library)支持,但这时线程本质上还轻量级进程. Java里的线程是由JVM来管理的,它如何对应到操作系统的线程是 ...
- java线程安全总结
转自:http://blog.csdn.net/haolongabc/article/details/7249098 最近想将java基础的一些东西都整理整理,写下来,这是对知识的总结,也是一种乐趣. ...
- Java线程间通信-回调的实现方式
Java线程间通信-回调的实现方式 Java线程间通信是非常复杂的问题的.线程间通信问题本质上是如何将与线程相关的变量或者对象传递给别的线程,从而实现交互. 比如举一个简单例子,有一个多线程的 ...
随机推荐
- java引用数据类型之Scanner与Random
一 Scanner类 引用数据类型的使用 与定义基本数据类型变量不同,引用数据类型的变量定义及赋值有一个相对固定的步骤或格式. 数据类型 变量名 = new 数据类型(); 每种引用数据类型都s ...
- Android 开发学习进程0.17 Android资源文件selector textview显示两种不同字体
selector 是安卓资源文件的一种,它可以使按钮等实现不同状态下的不同UI,不用在代码中实现,而使用方式有两种,一种在color文件下 创建.xml可以使按钮等字体在不同状态下的变化,其二是在dr ...
- SpringBoot ---yml 整合 Druid(1.1.23) 数据源
SpringBoot ---yml 整合 Druid(1.1.23) 数据源 搜了一下,网络上有在配置类写 @Bean 配置的,也有 yml 配置的. 笔者尝试过用配置类配置 @Bean 的方法,结果 ...
- jupyter 安装 卸载 包
# 安装 !pip install 库名 # 卸载 !pip uninstall 库名 -y
- python利用爬虫获取百度翻译,爱词霸翻译结果,制作翻译小工具
先看效果展示(仅作学习使用,非商业) 效果图是采用的 爱词霸 翻译,百度翻译 也实现了,只不过被注释了. 学计算机很多时候碰到生词,每次打开手机/浏览器翻译总觉得很麻烦,就想着自己写一个软件,自己去实 ...
- NOIP2007 树网的核 [提高组]
题目:树网的核 网址:https://www.luogu.com.cn/problem/P1099 题目描述 设 T=(V,E,W)T=(V,E,W) 是一个无圈且连通的无向图(也称为无根树),每条边 ...
- failed to find romfile "vgabios-stdvga.bin"
问题:failed to find romfile "vgabios-stdvga.bin" 解决: apt-get install vgabios ln -s /usr/shar ...
- First-Spike-Based Visual Categorization Using Reward-Modulated STDP
郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! Abstract 强化学习(RL)最近以击败欧洲围棋冠军等重大成就重新受到欢迎.在这里,我们第一次表明,RL可以有效地用于训练一个脉冲神经 ...
- 图数据库对比:Neo4j vs Nebula Graph vs HugeGraph
本文系腾讯云安全团队李航宇.邓昶博撰写 图数据库在挖掘黑灰团伙以及建立安全知识图谱等安全领域有着天然的优势.为了能更好的服务业务,选择一款高效并且贴合业务发展的图数据库就变得尤为关键.本文挑选了几款业 ...
- Android 引入第三方类库