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线程本质的更多相关文章

  1. 面试官:都说阻塞 I/O 模型将会使线程休眠,为什么 Java 线程状态却是 RUNNABLE?

    摘要: 原创出处 https://studyidea.cn 「公众号:程序通事 」欢迎关注和转载,保留摘要,谢谢! 使用 Java 阻塞 I/O 模型读取数据,将会导致线程阻塞,线程将会进入休眠,从而 ...

  2. Java 线程安全问题的本质

    原创声明:作者:Arnold.zhao 博客园地址:https://www.cnblogs.com/zh94 目录: 线程安全问题的本质 理解CPU JVM虚拟机类比于操作系统 重排序 汇总 一些解释 ...

  3. java线程 - 多线程 - 守护线程

    1.多线程执行者/处理类 都是Runnable的实现类(如自定义类实现Runnable 或 java原生的Thread.FutureTask),但最后都必须封装成Thread线程类由Thread.st ...

  4. java线程(2016-4-7)

    Thread.yield()的调用是对线程调度器(Java线程机制的一部分,可以将CPU从一个线程转移到另一个线程)的一种建议,它在声明:"我已经执行完生命周期中最重要的部分了,此刻正是切换 ...

  5. java线程内存模型,线程、工作内存、主内存

    转自:http://rainyear.iteye.com/blog/1734311 java线程内存模型 线程.工作内存.主内存三者之间的交互关系图: key edeas 所有线程共享主内存 每个线程 ...

  6. java线程详解(三)

    java线程间通信 首先看一段代码 class Res { String name; String sex; } class Input implements Runnable { private R ...

  7. Java线程与Linux内核线程的映射关系[转]

    Linux从内核2.6开始使用NPTL (Native POSIX Thread Library)支持,但这时线程本质上还轻量级进程. Java里的线程是由JVM来管理的,它如何对应到操作系统的线程是 ...

  8. java线程安全总结

    转自:http://blog.csdn.net/haolongabc/article/details/7249098 最近想将java基础的一些东西都整理整理,写下来,这是对知识的总结,也是一种乐趣. ...

  9. Java线程间通信-回调的实现方式

    Java线程间通信-回调的实现方式   Java线程间通信是非常复杂的问题的.线程间通信问题本质上是如何将与线程相关的变量或者对象传递给别的线程,从而实现交互.   比如举一个简单例子,有一个多线程的 ...

随机推荐

  1. js 自定义属性操作

    自定义属性操作     element.属性 获取内置属性值     element.getAttribute("属性") 我们自己添加的属性叫自定义属性     element. ...

  2. day25:魔术方法

    目录 1.__del__(析构方法) 2.魔术方法:__str__ 3.魔术方法:__repr__ 4.魔术方法:__call__ 5.魔术方法:__bool__ 6.魔术方法:__add__& ...

  3. Libsvm java工程实践

    在上篇文章中对libsvm的流程和简单的java代码测试做了说明,本篇简单对libsvm如何在工程中实践进行简短说明,不当的地方欢迎大家指正. 第一步是对libsvm的预测函数进行调整,我是从svm_ ...

  4. ALGEBRA-3 线性映射

    不求甚解 [零空间] 零空间对加法和标量乘法封闭,因此属于子空间:

  5. 2020-07-22:你觉得使用redis的主从复制的时候有什么点需要注意的吗?

    福哥答案2020-07-22: 1.主从同步缓冲区设定大小,如果进行全量复制耗时太长,进行部分复制时发现数据已经存在丢失的情况,必须进行第二次全量复制,致使slave陷入死循环状态.在全量复制的时候, ...

  6. wordpress-技术博客主题推荐

    推荐主题 1.WordStar 这个主题是干净的,以博客为中心,设计清晰,简单,直接的排版,可在各种各样的屏幕尺寸可读,适合多种语言. 效果图 还是非常简洁, 基本和CSDN差不多了 除了没有广告以外 ...

  7. OptaPlanner的新约束表达方式 Constraint Streams

    有好些时间没有写过关于OptaPlanner的东西了,其实近半年来,OptaPlanner还是推出了不少有用.好用的新特性.包括本文讲到的以Stream接口实现评分编程.关于OptraPlanner的 ...

  8. PythonCrashCourse 第九章习题

    创建一个名为Restaurant 的类,其方法__init__() 设置两个属性: restaurant_name 和cuisine_type 创建一个名为describe _restaurant ( ...

  9. JavaScript学习系列博客_13_JavaScript中的对象(Object)简介

    对象 对象属于一种复合的数据类型,在对象中可以保存多个不同数据类型的属性.除了那5种基本数据类型,就是对象. 分类:1.内建对象- 由ES标准中定义的对象,在任何的ES的实现中都可以使用- 比如:Ma ...

  10. SQL关键字的执行顺序

    1.Mysql执行顺序,即在执行时sql按照下面的顺序进行执行: from on join where group by having select distinct union order by 2 ...