首页 > 其他分享 >多线程-从os层面理解常见概念

多线程-从os层面理解常见概念

时间:2023-04-25 18:13:55浏览次数:41  
标签:调用 Java 层面 线程 内核 pthread run 多线程 os

如何创建一个线程

  1. 在Linux系统中有一个方法,他有四个参数,其中第一个参数是利用指针传入,后期如果被修改也会同步修改,第三个参数和自己定义的run方法有关,后面会详细说。
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, 
void *(*start_routine) (void *), void *arg); 

1682414016166

2.对比linux上和java启动一个线程的区别,首先是linux,其次是Java,linux就不必说了直接调用pthread_create,主要看Java(这里涉及到jni,下面有解释),thread.start->native start0();这里主要是Java通过jni调用c的方法并将其转化成c能理解的方式,然后然后传给pthread_create的回调函数中,在这个回调函数中,jni调用Java的run,线程就会执行我们的代码。

//头文件
#include <pthread.h>
#include <stdio.h>
//定义一个变量,接受创建线程后的线程id
pthread_t pid;
//定义线程的主体函数
假设有了上面知识的铺垫,那么可以试想一下java的线程模型到底是什么情况呢?
在java代码里启动一个线程的代码
这里启动的线程和上面我们通过linux的pthread_create函数启动的线程有什么关系呢?只能去可以查
看start()的源码了,看看java的start()到底干了什么事才能对比出来。start方法的源码的部分截图
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(100);
printf("main\n");
return 0;
}
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();
}
}
JNI(Java Native Interface)是Java语言中的一种机制,它允许Java与其他非Java程序进行交互。JNI为Java应用程序提供了本地方法调用机制,这意味着Java程序可以调用由非Java编写的本地库中的函数。

在使用JNI时,需要使用Java编程语言和C/C++编程语言进行配合,并按照特定的格式定义本地方法。然后使用Java的工具将Java源代码编译成字节码,并使用C/C++编译器将本地方法编译为共享库,最后在Java程序中加载并调用该共享库。

JNI被广泛应用于跨平台开发中,例如在Android开发中使用JNI可以调用本地特定平台的API,或者将Java应用程序与C/C++模块混合使用等等。
jni: 在Java中,`Runnable`接口(或继承`Thread`类)的`run`方法就是一段我们想要让线程执行的代码。当Java线程启动后,运行的就是其`run`方法。

而在C/C++中,在调用`pthread_create`函数时需要传递一个回调函数,该回调函数会在新线程中运行。从Java的角度看,我们可以将实现了`Runnable`接口的Java对象作为参数传入C/C++的回调函数中,在回调函数中再调用该Java对象中的`run`方法。

具体地说,我们可以实现一个Java类,在其中添加`run`方法,该方法用于存放我们要在线程中运行的代码。然后创建一个实例化对象,并将该对象作为参数传递给`pthread_create`函数所调用的C/C++回调函数中。在该回调函数中,我们可以通过JNI调用Java对象的`run`方法,从而在新线程中执行我们期望运行的代码。

总之,Java中的`run`方法和C/C++中`pthread_create`函数的回调参数之间不存在直接的映射关系,我们需要通过JNI进行函数调用,将Java对象转换成C/C++能够理解的形式,并手动调用其中的特定方法(如`run`方法)。

Java的线程模型:os层面分用户线程,内核线程

1.用户线程是运行内核线程上的,至于它们之间的对应关系有四种,1:1,1:n,n:n,n:1,至于具体什么样得具体分析,jvm是1:1,优点就是线程模型简单,缺点就是自己写东西容易引进用户态内核态频繁切换,或者弄出来大量线程,很影响系统性能;

2.如何确定什么时候是内核态什么时候是用户态

首先进程是运行在内存中的,但是内存有限大,需要运行在虚拟地址上,实际执行在运行在物理地址上就是通过mmu(具体解释看下main)转换的;然后cpu有四种不同的执行级别,0是内核态,3是用户态,另外俩不知道是啥,当你调用系统的方法就会进入内核态,比如park,sleep,mutex(具体原因看下面);cas不会引起切换,因为他只是一条cpu指令很快

3.至于cpu上下文切换

cpu上下文是cpu计数器和cpu寄存器,cpu上下文切换就是cpu加载这些任务,然后通过计数器在这些任务里切换(专业术语看下面),这里面涉及到进程之间,线程之间,

CPU使用虚拟地址向内存寻址,通过专用的内存管理单元(MMU)硬件把虚拟地址转换为真实的物理
地址
在Java中,`park`和`await`方法都可以使当前线程挂起(暂停执行),并等待其他线程的通知或者特定条件的满足。而`sleep`方法则是让当前线程进入休眠状态,在一段时间后再唤醒线程。

在Java的实现中,`park`、`await`和`sleep`方法都会涉及到操作系统的相应操作,因此它们内部的实现代码必然会有切换到内核态的操作。具体来说,当调用这些方法时,JVM会使用底层操作系统的原语来进行同步和线程调度,这些原语往往需要在内核态下执行。

而对于`Mutex`,它是一种互斥锁机制,用于控制多个线程对共享资源的访问,防止出现资源竞争和数据不一致等问题。在Java中,`Mutex`可以由`synchronized`关键字实现,也可以通过显式创建`ReentrantLock`对象来实现。

当使用`synchronized`关键字时,其内部实现会直接利用Java虚拟机的监视器锁机制,避免了上下文切换和用户态到内核态的转换。当使用`ReentrantLock`对象时,其内部实现则采用了基于CAS操作的自旋锁机制,也能够在多线程环境下保证共享资源的安全访问,但是使用自旋锁机制会导致CPU持续消耗大量的资源。

因此,在Java中执行`park`、`await`、`sleep`和`Mutex`的不同形式都可能涉及到操作系统的原语,从而需要在内核态下进行相应操作。
什么是 CPU 上下文切换
就是先把前一个任务的 CPU 上下文(也就是 CPU 寄存器和程序计数器)保存起来,然后加载新任务的
上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。
而这些保存下来的上下文,会存储在系统内核中,并在任务重新调度执行时再次加载进来。这样就能保
证任务原来的状态不受影响,让任务看起来还是连续运行

如何确定一个锁是什么锁

1.在os中的一种同步机制为了保护临界资源,常见的是mutex 和 semaphore

2.在jvm的mark word中会标记当前的锁,看下面的几个例子看如何判断锁

01偏向锁或者无锁

00 轻量锁

10重量锁(看到有的人写11是重量锁,默认他写错了)

11gc

第一个可能是无锁,或者是偏向锁,前提我没有打印hash,看第一个8位二进制的后俩位 01,有的资料说再往前一位是记录 当前锁是否可以是偏向锁的标志位比如101 ,没模出来

1682416446511

第二个重量锁

1682416637196

第三个轻量锁

1682416666861

3.sychronize 是什么锁

他三种锁都可能是,这个下一次看源码说

标签:调用,Java,层面,线程,内核,pthread,run,多线程,os
From: https://www.cnblogs.com/xiaoshahai/p/17353441.html

相关文章

  • 多线程批量解压
    importthreadingimporttimeimportosimporttarfileinput_path=r"D:\jieyaqian"out=r'D:\jieyahou'classs=os.listdir(input_path)defrepress(folder,input_path,out):print(1,folder)ori_tif=os.path.join(input_......
  • centos7下安装ifconfig 命令
    1,查找安装包 [root@localhostnetwork-scripts]#yumsearchifconfig已加载插件:fastestmirrorLoadingmirrorspeedsfromcachedhostfile*base:centos.ustc.edu.cn*extras:centos.ustc.edu.cn*updates:centos.ustc.edu.cn===================================......
  • iOS MachineLearning 系列(4)—— 静态图像分析之物体识别与分类
    iOSMachineLearning系列(4)——静态图像分析之物体识别与分类本系列的前几篇文件,详细了介绍了Vision框架中关于静态图片区域识别的内容。本篇文章,我们将着重介绍静态图片中物体的识别与分类。物体识别和分类也是MachineLearning领域重要的应用。通过大量的图片数据进行训练后,模......
  • Nginx + Nacos2.x集群配置
    Nginx:#集群配置http{upstreamnacos-cluster{ip_hash;server127.0.0.1:8858;server127.0.0.1:8868;server127.0.0.1:8878;}server{listen8838;server_namelocalhost;}location/nacos{ ......
  • centos linux系统安装详解
    打开vmware,版本差异区别不大选择创建新的虚拟机  选择典型,是默认选项不用改,点击下一步 选择稍后安装操作系统(默认选项不用改),点击下一步 选择linux,并且版本改为centos64位,点击下一步 虚拟机名称随便改,位置是指虚拟机的位置,点击浏览,自己选择位置,点击下一步 最大......
  • 如何建设一个用于编译 iOS App 的 macOS 云服务器集群?
    作者:京东零售叶萌现代软件开发一般会借助CI/CD来提升代码质量、加快发版速度、自动化重复的事情,iOSApp只能在mac机器上编译,CI/CD工具因此需要有一个macOS云服务器集群来执行iOSApp的编译。今天就来谈谈如何建设macOS云服务器集群购买macmini/MacStudio机......
  • golang 通过 os 包进行文件读写
    go中os包主要与操作系统打交道,实际底层还是通过相关的系统调用实现文件的读写操作,今天我们就来聊聊通过os包实现文件的读写操作。我们在使用os包进行相关操作时,主要流程:读操作open->read->close写操作open->read->write->close总体来说,读写操作都......
  • gcc 中-O -O1 -O2 -O3 -Os -Ofast -Og优化的原理
    一般来说,如果不指定优化标识的话,gcc就会产生可调试代码,每条指令之间将是独立的:可以在指令之间设置断点,使用gdb中的p命令查看变量的值,改变变量的值等。并且把获取最快的编译速度作为它的目标。    当优化标识被启用之后,gcc编译器将会试图改变程序的结构(当然会在保证变换之后......
  • 创信国产操作系统uos桌面卡死的解决办法
    如果是整个桌面卡死,不要按主机电源键强制关机,重启后有可能会有配置文件缺失的问题。----首先尝试:按Ctrl+Alt+F2,进入tty2输入用户名,回车输入密码,回车输入命令回车:killallkwin_x11按Ctrl+Alt+F1,回到桌面----如果还是没有缓解:按Ctrl+Alt+F2,进入tty2按Ctrl+......
  • linux之dlopen、dlsym和dlclose使用和举例
     之前用过这三个函数一直没时间整理一下。今天抽时间整理一下。1、函数简介dlopen基本定义功能:打开一个动态链接库 包含头文件: #include<dlfcn.h> 函数定义: void*dlopen(constchar*pathname,intmode); 函数描述: 在dlopen的()函数以指......