文章迁移自语雀。原文地址:https://www.yuque.com/changhe-xqeca/zn1cvu/dvunld
昨晚上感觉程程是个温柔的姑娘
1.同步的实现:
是利用锁的机制来实现同步的。
锁机制有如下两种特性:
互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机制,这样在同一时间只有一个线程对需同步的代码块(复合操作)进行访问。互斥性我们也往往称为操作的原子性。
可见性:必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作从而引起不一致。
2.synchronized的用法
根据修饰对象分类
1、同步方法
(1) 同步非静态方法
public synchronized void methodName(){
// method
}
(2) 同步静态方法
public synchronized static void methodName(){
// method
}
2、同步代码块
synchronized(this|object) {}
synchronized(类.class) {}
private final Object MUTEX =new Object();
public void methodName(){
synchronized(MUTEX ){
//……
}
}
根据获取的锁分类
1、获取对象锁
synchronized(this|object) {}
修饰非静态方法
在 Java 中,每个对象都会有一个 monitor 对象,这个对象其实就是 Java 对象的锁,通常会被称为“内置锁”或“对象锁”。类的对象可以有多个,所以每个对象有其独立的对象锁,互不干扰。
可以使用private static Object lock= new Object() 作为一个专用的持有锁的对象.
2、获取类锁
synchronized(类.class) {}
修饰静态方法
在 Java 中,针对每个类也有一个锁,可以称为“类锁”,类锁实际上是通过对象锁实现的,即类的 Class 对象锁。每个类只有一个 Class 对象,所以每个类只有一个类锁。Java的对象的字节码对象.
在 Java 中,每个对象都会有一个 monitor 对象,监视器。
1) 某一线程占有这个对象的时候,先monitor 的计数器是不是0,如果是0还没有线程占有,这个时候线程占有这个对象,并且对这个对象的monitor+1;如果不为0,表示这个线程已经被其他线程占有,这个线程等待。当线程释放占有权的时候,monitor-1;
2) 同一线程可以对同一对象进行多次加锁,+1,+1,重入性 synchronized 支持重入.
3.synchronized原理分析
第一份的源码是为了看线程信息的, 第二份是为了看反编译之后的信息的.
第一份程序源码
public class Demo {
public static void main(String[] args) {
(new Thread(() -> {
sleep();
})).start();
(new Thread(() -> {
sleep();
})).start();
(new Thread(() -> {
sleep();
})).start();
(new Thread(() -> {
sleep();
})).start();
}
private static synchronized void sleep() {
System.out.println(Thread.currentThread().getName() + "now is sleep ");
try {
TimeUnit.SECONDS.sleep(50L);
} catch (InterruptedException var1) {
var1.printStackTrace();
}
}
}
第二份的源码:
1.线程的堆栈查看
运行Demo的main方法, 找到本地jdk的 jconsole.exe文件, 打开
选择要链接的正在运行的java进程, 直接选择我们的自己的Demo
点到线程 这里,就可以看到正在运行的所有线程了. 我们自己创建的Thread0 -4 都在, 当前选中的的
下一个就是表名了锁的拥有者是Thread-3
再次运行, 有一个新的进程号, 获取到进程号7044
输入命令 jstack 7044, 就能查看到具体的堆栈信息了.
命令提示待
2.字节码分析
打开Demo.class 和 Demo2.class文件所在的文件夹, 打开黑窗口,
使用命令 javap -v Demo.class 查看此文件的分析
可以看得出来, 当syncronized加在静态方法上的时候,是没有monitorenter / monitorexit出现的,
使用命令 javap -v Demo2.class 查看此文件的分析, 可以看到 存在一个monitorenter 和两个 monitorexit出现. 原因是:
第一个是为了 Exit the monitor associated with this
退出当前的this关联的监控
第二个退出是 Be sure to exit the monitor!
保证退出当前的监控.
monitorenter 的作用:
Enter the monitor associated with object
进入这个对象关联的监控
待续....
1 人点赞
1
长河
2020-06-02 10:28
15