小白谈谈Synchronized那些事(二)

一个进程里面 空间是共享的

多个线程 共享 进程的数据域,共享进程的堆区

如果 多个线程 操作一个进程会导致一个什么问题

数据不同步?   数据出错了 ?

以上不管怎样执行,每次执行输出的打印都不一样。

那这个时候,数据不同步了

这个时候 咋搞?

回答: 加锁

就是  synchronized

why?加了锁 为啥还是 没有同步?

回答:因为主线程的原因,fork出来的其他线程,只有等其他线程执行完毕了,主线程才会结束。

那么,如何解决?

回答:让主线程睡一会

这个时候,就达到我们想要的效果了,这就是加锁,同步了

主线程   会等待 它的  附属守护线程 执行完毕后

主线程 才会退出~(这就是为啥要睡一秒的原因)

守护线程  优先级是最低的

JVM在启动的时候开启两个线程

1 垃圾回收

2 主线程


那么接下来,谈谈volatile  

这个时候,发现,

1 加了 volatile 关键字

2 去掉了 synchronized关键字 

3 加了 join() 

出现的效果,跟加锁一样的效果。

实际上,这样做的效果 就是 多线程的并发


多线程  多线程  从字面上看 ,就是多个线程的同时执行
上面是没有锁的并发执行着,但是呢?加上了 join().其实就是插队了,耍无赖。并且并发的线程这个时候,还要等这个插队的无赖先执行完,才能执行,所以也就看到了这样的加锁的一样的效果

but,再来看看一个奇怪的东东

发现 去掉了 volatile后,还是可以保证同步

其实,这就考查到了 volatile究竟是干嘛的了

volatile  只是可见性,不能保证原子性

单独用 么有什么用,也就只能保证一个 可见性而已

要与 CAS一起用

每个线程跑 不依赖上个线程的状态

Next,再来研究谈谈

这个时候,发现

1 不要 volatile

2 添加synchronized

3 去除join()

这个时候,心里估计又是在嘀咕了,怎么又不能同步了呢?

其实 这是由于  跟上文提到一样,主线程还没执行完

1 ACC_SYNCHRONIZED  线程标识

2 invokedynamic             线程独有


线程同步,想到的都是 synchronized加锁,那么他的原理是啥?

如果是 synchronized加在静态方法上

在字节码是无法看到它锁了,事实上是锁了整个类,也就是Class

so,在这里 就来谈谈一般实例方法

public class ThreadSynTest extends  Thread {
    public  int count;
    public  void addLock() {
        count += 1;
    }
    @Override
    public void run() {
       //给当前对象加锁
       synchronized (this) {
           addLock();
       }
    }
    public static void main(String[] args)  {
        new  ThreadSynTest().start();
    }
}

看看底层 原理是啥

在执行run() 方法的时候

首先 aload_0 其实就是 this

然后 monitorenter  

当monitorenter  进来后,就锁住了,其他对象就进不来了

然后这里又会涉及对象的概念

  1. 对象头 (锁标志位 持有该对象的线程数)

  2. 数据区

  3. 对齐填充

偏向锁  当线程第一次来了后

             做一个标记,当下次还是这个对象进来的时候,就不上锁了

but why  ?  monitorexit 会出现两次

看看字节码,在这里,这字节码也不复杂,自己来解读一下吧!

         0: aload_0
         1: dup
         2: astore_1
         3: monitorenter
         4: aload_0
         5: invokevirtual #3                  // Method addLock:()V
         8: aload_1
         9: monitorexit
        10: goto          18
        13: astore_2
        14: aload_1
        15: monitorexit
        16: aload_2
        17: athrow
        18: return

这里 先回顾下 栈的知识

栈:栈帧 (局部变量表、操作数栈、指向常量池的索引、返回地址、、、)

0 :将0 槽位 也就是 this  也就是当前对象

      推送至栈顶

1: 进行复制,入栈

2: 将栈顶存入局部有变量表

3: 对象监视锁

4: 将局部变量推送至栈顶

5: 实例化addLock()方法

8:将局部变量推送至栈顶

9: 对象监视锁释放

10:跳转到18 return 退出

13:将栈顶存入局部有变量表

14:将局部变量推送至栈顶

15:  对象监视锁释放

16: 将局部变量推送至栈顶

17:抛出异常

18:return 退出

从以上,可以看到,monitorexit 出现了两次,why?

这就是为啥 出现了两次的原因,抛出 了异常,锁要进行释放

1 一个是正常退出

2 另一个是 出现异常后释放锁,防止死锁

好了,这两篇也就算是自己谈谈Synchronized

若有理解,想法不对的地方,敬请批评指出

赶快来分享关注吖

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值