并发编程1

并发编程1

编译openjdk源码

  • 怎么看这个方法,在github上下载open jdk方法
  • 为什么下的是jdk11,编译jdk11必须要有jdk8的代码(编译jdk源码,必须在目录下有一个比它版本低的jdk源码)
  • native方法是通过JNI方法调用的,对应于一个c语言方法,hotspot大部分基础功能都通过openjdk开源了

java中的线程和操作系统的线程是什么关系

  • java线程的本质

  • start方法启动后,调用软方法run()

start()源码的线程控制原语

  • start0()是一个native方法,对应于openjdk中的Thread.c(对应于Thread.java),关联到 jvm_startThread()方法
jvm_startThread()在jvm.cpp
  • 实例化一个c++对象 JavaThread
  • MutexLocker()是一个很重要的方法
  • 然后根据操作系统类型,如果是linux,就会调用os_linux.c下面pthread_create()方法
pthread_create()
  • 在os_linux.cpp文件里面

  • int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);
    
具体的参数
  • 根据man配置的信息可以得出pthread_create会创建一个线程,这个函数是linux系统的函数,可以用C
    或者C++直接调用,上面信息也告诉程序员这个函数在pthread.h, 这个函数有四个参数,这四个参数由glibC提供

  • pthread_t *thread:传出参数,调用之后会传出被创建
    线程的id,定义 pthread_t pid; 继而 取地址
    &pid

  • const pthread_attr_t
    *attr: 线程属性,关于线程属性是linux
    的知识,一般传NULL,保持默认属性

  • void(start routine)(void *):线程的启动后的主体函数,会回调java线程中的run()方法,需要你定义一个函数,然后传函
    数名即可

  • void *arg:参数,非必须

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(100); 
        printf("main\n");
    }
    

总结

  • 下载一个clion的idea

  • 为什么下的是jdk11,编译jdk11必须要有jdk8的代码,下载11、12的代码

  • idea中进行debug,配置选项

    • debug argument :com.shadow.app.ThreadDemo
  • 需要把自己编译的类放到虚拟机中的bin目录下

  • debug过程中,会启动很多线程,所以跳过一些断点,才会跳到os_linux.cpp()中的pthread_create()是由自己编译的类实现的

  • aqs比sysnchronized的效率高

    • aqs压根就没有调过c++的代码,除非到park线程的阶段,这样才叫重量锁!而cas这种没有线程切换的过程是轻量锁。
  • 启动过程

    • Thread.start()
    • native Thread.start0()
    • JVM 实例化一个c++对象JavaThread(JVM_ENTRY–宏)
    • 判断os,如果是linux系统,会调用pthread_create()

实现JNI调用

  • package com.shadow.app;
    public class ZLThread {
      //装载库,保证JVM在启动的时候就会装载,故而一般是也给static
     static {
       System.loadLibrary( "EnjoyThreadNative" );
     }
     public static void main(String[] args) {
       ZLThread zLThread =new ZLThread();
       // tnew.c.start1()
       zLThread.start1();
     }
     private native void start1();
    }
    
  • 自定义JNI对应的java代码已经有了,还需要些c语言的代码

启动步骤
  • 1.javah编译一个so文件

    • javah在java9之后就没有了

    • java11之后javac ZLThread.java

      javac -h . ZLThread.java(java11中间有一个点,要注意)

    • 会多一个com_shadow_app_ZLThread.h文件

    • #include<jni.h>
      #ifndef _Included_com_shadow_app_ZLThread
      #define _Included_com_shadow_app_ZLThread
      #ifdef __cplusplus
      extern "C"{
      #endif
      JNIEXPORT void(JNICALL Java_com_shadow_app_ZLThread_start1(JNIEnv *, jobject);
      
      #ifdef __cplusplus
      }
      #endif
      #endif
      
  • 2.需要把上一步生成的.h文件中的方法名复制到自己的.c文件中

    • 本地方法的代码编写( tnew.c文件)

    • #include <pthread.h>
      #include <stdio.h>
      #include "com_shadow_app_ZLThread.h"
      //定义变量接受线程id
      pthread_t pid;
      //线程的主体方法相当于 java当中的run
      void* thread_entity(void* arg) {
        //子线程死循环
        while(1){
          //睡眠100毫秒
          usleep(100);
          //打印
          printf("I am new Thread\n"); 
       }
      }
      //c语言的主方法入口方法,相当于java的main
      JNIEXPORT void(JNICALL Java_com_shadow_app_ZLThread_start1(JNIEnv *, jobject) {
        //调用linux的系统的函数创建一个线程
        pthread_create(&pid,NULL,thread_entity,NULL);
        //主线程死循环
        while(1){
          //睡眠100毫秒
          usleep(100);
          //打印
          printf("I am main\n");
       }
      }
      
  • 3.把.c文件转换成.so文件

    • gcc -fPIC -I /usr/lib/jvm/java-1.8.0-openjdk/include -I /usr/lib/jvm/java-1.8.0-openjdk/include/linux -shared -o libLubanThreadNative.so threadNew.c

    • gcc -fPIC -I /home/shadows/soft/jdk11/include -I /home/shadows/soft/jdk11/include/linux -shared -o libEnjoyThreadNative.so tnew.c

  • 4.需要把.so文件所在目录加到linux需要加载的资源目录中,这样java文件才能找到libEnjoyThreadNative.so文件

    • export LD_LIBRARY_PATH=&LD_LIBRARY_PATH:{libLubanThreadNative.so}

    • export LD_LIBRARY_PATH=&LD_LIBRARY_PATH:/home/shadows/enjoy/com/shadow/app

  • 5.运行java文件

    • java com.shadow.app.ZLThread
    • 启动成功的话,死循环打印I am new Thread和I am main

答疑

1.java中的线程内容是跟操作系统中的线程对应的

2.怎么解决事务补偿

  • 订单->支付-(mq)->发红包->加积分

  • 假设发红包挂掉了,肯定不能回滚,用户钱都没了

  • 等服务起来,去做事务补偿

  • 通过幂等解决(某一个方法有10行,运行了5行,在这里挂掉了,服务恢复后,不能重复前5行)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值