线程创建(JVM源码分析)&&synchronized原理&&Monitor机制
2021-01-11 11:53:34 0 举报
线程创建(JVM源码分析)
作者其他创作
大纲/内容
绑定完成后,方法下面的方法进行启动src/hotspot/share/prims/jvm.cpp:3118
src/hotspot/share/include/jvm.h:260
线程1释放后,线程2竞争到锁,进入
native_thread->prepare(jthread);
线程2
void os::pd_start_thread(Thread* thread)
创建JavaThread
唤醒线程执行run方法
java.lang.Thread#start
src/hotspot/share/prims/jvm.cpp:3063
src/hotspot/os/linux/os_linux.cpp:661
进入入口队列
执行run方法src/hotspot/share/runtime/thread.cpp:371
共享资源所有者
线程1
this->run();
等待锁释放才能重新进入
notify唤醒
java.lang.Object 类定义了 wait(),notify(),notifyAll() 方法,这些方法的具体实现,依赖于一个叫 ObjectMonitor 模式的实现,这是 JVM 内部基于 C++ 实现的一套机制monitor 的机制中,monitor object 充当着维护 mutex以及定义 wait/signal API 来管理线程的阻塞和唤醒的角色。任何一个 Java 对象都可以作为 monitor 机制的 monitor object
java.lang.Thread#registerNatives
monitorexit方法
根据映射调用对应的方法
void JavaThread::run()
获取到监视器锁进入
根据不同的操作系统进行启动OSThread线程
判断系统类型选择对应的操作系统的cpp
void Thread::call_run()
src/hotspot/share/runtime/thread.cpp:1748一个新的Java线程调用的主例程
pd_start_thread(thread);
monitorenter方法
src/hotspot/share/runtime/thread.cpp:495
os::start_thread(thread);
src/hotspot/share/runtime/thread.cpp:1782
核心方法:
所有新创建线程的线程启动例程*thread_native_entry(Thread *thread)
sync_with_child->notify();
synchronized原理
等待队列
一、特性:互斥性 :synchronized修饰的代码块、实例方法、静态方法,多线程并发访问时,只能有一个线程获取到锁,其它线程都处于阻塞等待可见性: 某线程 A 对于进入 同步块之前或在 synchronized 中对于共享变量的操作,对于后续的持有同一个监视器锁的其他线程可见二、Synchronized加锁方式 :修饰实例方法,锁是当前实例对象 public synchronized void test(){}修饰类方法,锁是当前类对象 public static synchronized void test(){}修饰代码块,锁是括号里面的对象 synchronized (this){}三、重量级锁底层原理:汇编语言:1、同步方法和同步代码块底层都是通过monitor来实现同步的。每个对象都与一个monitor相关联2、同步方法是通过方法中的access_flags中设置ACC_SYNCHRONIZED标志来实现;同步代码块是通过monitorenter和monitorexit来实现。两个指令的执行是JVM通过调用操作系统的互斥原语mutex来实现,被阻塞的线程会被挂起、等待重新调度,会导致“用户态和内核态”两个态之间来回切换,对性能有较大影响Java代码:手动加锁解锁:UnsafeFactory.getUnSafe().monitorenter和monitorexit来实现
src/hotspot/os/linux/os_linux.cpp:977
一直循环等待,一直到os::start_thread调用
调用native方法
所有者调用wait,占用共享资源的线程释放监视器锁,进入等待队列
JVM_StartThread
public class T1 { public static void main(String[] args) { SynchronizedTest synchronizedTest=new SynchronizedTest(); Thread thread1 = new Thread(synchronizedTest::test); Thread thread2 = new Thread(synchronizedTest::test); thread1.start(); thread2.start(); } static class SynchronizedTest{ private void test() { System.out.println(\"进入方法\"); synchronized (this){ System.out.println(\"进入synchronized代码块\"+Thread.currentThread().getName()); try {//会将监视器锁(Monitor锁)释放,当前线程进行等待队列,重新竞争监视器锁 wait(5000);//monitor机制没有sleep,因此不会释放锁,必须等线程出去后其他线程才能进入// Thread.sleep(500);//不能使用当前线程的wait,// 无论多线程还是单线程都会报错IllegalMonitorStateException- 如果当前线程不是此对象监视器的所有者。//此方法只应由作为此对象监视器的所有者的线程来调用。//根本原因:监视器锁是jvm分发给对象的,其他线程获取到这个对象的monitor锁只是将ObjectMonitor的_owner指向这个线程。//this调用wait时,会将ObjectMonitor的_owner置为null,并将当前线程记录到自己的等待队列中。// 而线程调用wait,等于要将这个线程的监视器的_owner指向自己改为null,自己放到自己的等待队列所以没法释放就抛出非法的监视器锁状态异常// Thread.currentThread().wait(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(\"结束synchronized代码块\"); } System.out.println(\"synchronized代码块外\"); } }}
核心方法:分配c++线程结构并创建本机线程。
将jvm的native线程native_thread与java中的线程jthread建立绑定关系src/hotspot/share/prims/jvm.cpp:3086
对象内存结构
Thread::start(Thread* thread)
唤醒线程
执行代码块结束释放锁
不同的操作系统有不同的实现,这里跟踪的是最常用的linux
代码实例
src/hotspot/share/prims/jvm.cpp:3039
获取到锁
void JavaThread::thread_main_inner()
src/java.base/share/native/libjava/Thread.c:43
JNINativeMethod建立了java代码与jni的映射
竞争锁,获取到锁的进入
入口队列
start0();
监视器机制Monitor机制
Thread::start(native_thread);
Thread初始化时调用的native方法
0 条评论
下一页