java.lang.thread_java学习-并发-java.lang.Thread API

java.lang.Thread API定义

new Thread 创建 Thread 对象

对于当前操作并不涉及os线程的创建,只涉及java对象的创建

Thread#start 启动线程: 这里主要实现 jvm 和 java 代码通信(调用)实现系统线程的创建和执行

Thread#join 等待线程执行完成: 本质是通过一直探测jvm中c++的javaThread对象是否存在,如果存在表示当前线程执行还未结束,反之则代表结束,这里的核心点在于object#wait操作

public static void main(String[] args) throws InterruptedException {

threadApi();

}

public static void threadApi() throws InterruptedException {

/**

* 在加载Thread.class 到jvm中时会执行当前Thread 类中的static代码块 以及 static变量

* 此时就会执行 registerNatives 的native 方法对应的就是 thread.c 中的 Java_java_lang_Thread_registerNatives 方法;

* 该方法的执行会将Thread中所有映射的native 方法和变量进行加载到jvm中

*/

// 创建一个线程对象,对于这里的操作只涉及到java层面的对象创建,并不涉及os线程操作;对于其中的属性操作

// target -> 当前线程对象指定的runnable方法

// group -> 线程组: 对于一个新的线程对象而言,默认会使用当前调用线程的所属线程组;

// 对于stackSize 属性在@since 1.4 后就可以人工指定,而不需要只使用 xss的限制

Thread thread = new Thread(() -> {

log.info("java.lang.Thread api 学习");

});

// 启动线程 : thread#start

/**

* start 首先是被synchronized 修饰表示当前方法操作是线程安全的同步操作: 因此就可以理解java language 规范中 happens-before 对于 start 和 run 的定义

* 在start 中 首先会将当前线程对象添加到thread.threadGroup; 然后会调用 start0(native)

* 对于start0是属于JNI方法,其对应的是jdk源码中的c++代码对应的就是"JVM_StartThread" 其对应的实现就是jvm.cpp中的 JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)) 方法;

* "java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) != NULL" 对于 当前判断是通过判断当前jobject 是否已被实例化,如果已经被实例化说明当前对象已被创建表示对应的线程已被创建; 因此对于一个Thread对象而言如果调用了多次start方法则会抛出 异常"java_lang_IllegalThreadStateException"-> 对应的就是 "java.lang.IllegalThreadStateException" 在openjdk中 使用了 "THROW(vmSymbols::java_lang_IllegalThreadStateException());" 来抛出异常,其映射是存在于 vmSymbols.h中的模板定义" template(java_lang_IllegalThreadStateException, "java/lang/IllegalThreadStateException") \"

*

* "native_thread = new JavaThread(&thread_entry, sz);" 此时会创建 JavaThread 对象, 在这里传递了两个参数一个是 "thread_entry方法的引用(类似于java lambda)",第二个参数为当前线程栈大小

* 对 "thread_entry"方法的分析:

* static void thread_entry(JavaThread* thread, TRAPS) {

* HandleMark hm(THREAD);

* Handle obj(THREAD, thread->threadObj()); // 该操作就是为了java Thread 对象

* JavaValue result(T_VOID);

* JavaCalls::call_virtual(&result, // 对于 call_virtual 实际就是执行的回调操作,该操作会调用java Thread#run 方法

* obj,

* SystemDictionary::Thread_klass(),

* vmSymbols::run_method_name(), // 此处就是将对应的 run方法加入其中

* vmSymbols::void_method_signature(),

* THREAD);

* }

* 此时进入 JavaThread::JavaThread(ThreadFunction entry_point, size_t stack_sz) 构造方法

* 1:执行当前JavaThread 对象的初始化操作:initialize()

* 2:判断当前线程类型时 java_thread 还是 compiler_thread, 此时会调用 os::create_thread(Thread* thread, ThreadType thr_type, size_t req_stack_size)

* 此时进入 os::create_thread(Thread* thread, ThreadType thr_type, size_t req_stack_size) (os_linux.cpp):

* 在当前代码的关键点就在于 pthread api的使用,利用POSIX_THREAD高级api来创建os线程;

* 对于 pthread_create第三个参数传递的 thread_native_entry 方法引用分析

* 重点在于对于 "thread->call_run();"通过调用 "JavaThread::run()" -> "JavaThread::thread_main_inner()" -> "this->entry_point()(this, this);" (这里可以看上面"thread_entry"的解释) -> 该操作是正式执行Thread#run回调;

* 当当前线程执行结束后会执行"JavaThread::post_run()" 进行资源回收

* 对于当前方法而言,有可能由于内存不足导致线程创建失败,通过

* // Allocate the OSThread object

* OSThread* osthread = new OSThread(NULL, NULL);

* if (osthread == NULL) {

* return false;

* }

* 来判断是否有空间创建线程对象;如果空间分配失败则表示线程创建失败,但其不会抛出OOM异常

* 对于 以下代码分析:

* if (native_thread->osthread() != NULL) {

* // Note: the current thread is not being used within "prepare".

* native_thread->prepare(jthread);

* }

* osthread() 实际是调用的 "thread.hpp中的 OSThread* osthread() const { return _osthread; }"

* 对于 os::create_thread 中如果OSThread 对象创建成功则会调用 "void set_osthread(OSThread* thread) { _osthread = thread; }",来设置 "_osthread" 属性,因此当对象OSThread 创建失败时,当前字段为null,因此可以通过当前字段判断线程是否真正创建成功

*/

thread.start();

// thread.start();// 抛出 IllegalThreadStateException

/**

* 阻塞等待当前线程执行结束

* 这里主要是通过调用 native java.lang.Thread#isAlive() 实现,对应的c++ 中的操作就是去获取JavaThread 对象是否存在,对于 thread#start 中 在c++中有一个操作就是在post_run方法中会进行资源回收,因此当c++中javaThread执行结束后,对象就会被资源回收,代表当前线程已经执行结束;

*

* 这里还有一点关于 Object#wait native 分析: 对于wait操作实际是直接执行膨胀锁并不会有偏向锁的存在

* 对于 Object#wait 对应的 jni 定义 存在于 jvm.h 的

* JNIEXPORT void JNICALL

* JVM_MonitorWait(JNIEnv *env, jobject obj, jlong ms);

* 其具体实现为 jvm.cpp 中的 "JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))" 主要为 调用 "ObjectSynchronizer::wait(obj, ms, CHECK);"

* 此时进入 synchronizer.cpp中的

* int ObjectSynchronizer::wait(Handle obj, jlong millis, TRAPS)

* 对于当前方法首先判断JVM是否支持偏向锁,如果支持偏向锁,"BiasedLocking::revoke(obj, THREAD);" 会对当前对象头执行偏向锁撤销操作

* 后续会直接调用 "ObjectMonitor* ObjectSynchronizer::inflate(Thread* self, oop object,const InflateCause cause)" 进入膨胀过程

* 对于膨胀的过程实际就是对 Inflated(已持有到锁) -> Stack-locked -> INFLATING -> Neutral -> BIASED 按照锁的粒度从高到低进行判断,最终转换为膨胀锁阶段 返回 ObjectMonitor;

* 对于当前inflate实际就是 object转换为 ObjectMonitor的过程

* 对于 ObjectMonitor分析 : 其中存在一个 waitSet 属性值, 其操作就是类似于 AQS 的双向队列

* ObjectWaiter* volatile _WaitSet; // LL of threads wait()ing on the monitor

* 对于 ObjectWaiter 也可以等价于 java.util.concurrent.locks.AbstractQueuedSynchronizer.Node

* 再次进入 objectMonitor.cpp中的

* void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS)

* 会首先创建一个ObjectWaiter 节点准备加入到等待队列中,会使用当前Thread的parkevent 执行reset进行重置挂起操作,使用OrderAccess.fence建立内存屏障

* 对于addWaiter 操作也是受到 spinlock的保护,因此需要 在入队之前先执行 Thread::SpinAcquire 操作 对于当前入队操作 和 java.util.concurrent.locks.AbstractQueuedSynchronizer#acquire(java.util.concurrent.locks.AbstractQueuedSynchronizer.Node, int, boolean, boolean, boolean, long) 操作类似, 不同点在于 对于 c++是直接使用了 spinLock;

* 对于 spinLock acquire 首先会执行cas操作作为fast,如果失败,则执行下一个阶段, 在此阶段如果为单核则直接阻塞当前线程; 反之则 会首先执行 线程 yield ,并执行cas操作如果操作持续失败,且yield次数达到阈值,则会执行线程休眠1ms操作,并直到cas操作成功,则加锁成功;

* 在执行AddWaiter 操作中 和 aqs node acquire不同点在于初始化链表时并不会创建一个无意义的头节点; 释放锁

* 调用 Thread#ParkEvent属性 的park 方法 实际 就是 os::PlatformEvent::park 内部使用了 POSIXThread中的相关的lock以及condition 相关api

*

*/

thread.join();

/**

* 分析 jdk.internal.misc.Unsafe#park(boolean, long)

* 对应的就是 unsafe.cpp中的 "UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, jlong time))" 其最终操作也是执行到了os::PlatformEvent::park 内部使用了 POSIXThread中的相关的lock以及condition 相关api

*/

}

public static void executors() {

ExecutorService executorService = Executors.newFixedThreadPool(2);

// 由于 core = 2, 当前只提交了一个任务,因此会理解创建任务,并创建新的thread对象,并调用start 方法来执行当前线程的runnable

executorService.submit(() -> {

log.info("线程启动");

});

executorService.shutdown();

}

对于这里大量的操作实际都是使用了 POSIX_Thread 高级api相关操作

标签:lang,java,Thread,thread,线程,当前,操作

来源: https://www.cnblogs.com/xingguoblog/p/13819033.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值