由synchronized闲谈锁机制

2019-01-04  本文已影响81人  土肥圆的诺诺

最近正在按照大神指点,一点点去复习知识,正好看到了Synchronized这块,本着多看一层可以装逼的思想,就有了这篇文章。
Synchronized可以说是我们经常用到的,也就是我们经常说的锁机制,我们为了防止多个线程访问保证单一和安全性,就采用了锁机制。Synchronized经常在以下几种情况下使用

public synchronized void printLog(String content) {
    for (int x = 0; x < 5; x++) {
        Log.e(TAG, "print: " + content + "---" + x);
    }
}

这种方法下,我们锁住的其实是类的实例化对象,只和调用方法的对象有关。

public static void printLog(String content) {
   for (int x = 0; x < 5; x++) {
       Log.e(TAG, "print: " + content + "---" + x);
   }
}

在这种情况下锁住的其实是类对象,不管多少个线程,多少个类的实例化对象,都得老实的排队进入。

public void printLog(String content) {
 synchronized (this) {
     for (int x = 0; x < 5; x++) {
         Log.e(TAG, "print: " + content + "---" + x);
     }
 }
}

这种情况下锁住的其实还是类对象,线程再多,对象再多,也得老实等着别人释放锁。

public void printLog(String content) {
    synchronized (DemoClass.class) {
        for (int x = 0; x < 5; x++) {
            Log.e(TAG, "print: " + content + "---" + x);
        }
    }
}

这种情况和上面一样,再多对象和线程也得老实等着别人释放锁。

private static final String TAG = "DemoClass";
public void print4(String content) {

    synchronized (TAG) {
        for (int x = 0; x < 5; x++) {
            Log.e(TAG, "print: " + content + "---" + x);
        }
    }
}

这种情况和上面一样,都是需要老实等待别人放锁才能进去。


通过上面我们基本可以总结出来什么呢?
作为锁的资源只要是独一份那种,那么作为对象来说,线程再多也是安全的。像上面加锁方法,是因为实例化以后,每个实例化对象自己内部会保存一份这个方法,锁并不是相同的一个。
静态资源和类文件,包括某个对象,从某种角度来说都是独一份的存在。 如果锁的是类对象的话,尽管new多个实例对象,但他们仍然是属于同一个类依然会被锁住,即线程之间保证同步关系。

其实我个人对锁这个词语一直不太满意,我比较喜欢用钥匙来理解。毕竟加锁的方法就好比带锁的房间,有钥匙才能进入,什么是钥匙呢?其实就是所谓锁的存在。
synchronized是怎么实现线程安全的?
这里其实牵扯到一个东西,叫对象的监视器即Monitor。每个对象自身都会带着一个Monitor,相当于一个钥匙。

synchronized代码块我们可以理解为一个带锁的屋子,每次只能进去一个人,作为锁的对象理解为把门人。当进入的时候,先到的线程就会找把门人要钥匙,说我要进去玩,把门人这时候有钥匙就把钥匙给了它,它就能进去。如果此刻来了其他线程,和把门人要钥匙,把门人摊手说,钥匙还么给我呢,等上个人还了钥匙再进去吧。这里的钥匙就是作为锁对象的Monitor。
syncrhoized又叫做内置锁,为什么呢?因为使用syncrhoized加锁的同步代码块在字节码引擎中执行时,其实是通过锁对象的monitor的取用与释放来实现的。由上面我们说道Monitor是内置于任何一个对象中的,syncrhoized利用monitor来实现加锁解锁,故syncrhoized又叫做内置锁。 所以syncrhoized(lock)来加锁时,锁对象可以是任意对象了。
详情大家可以参考这篇文章
https://www.cnblogs.com/ygj0930/p/6561667.html
这里可以简单讲一下重入锁概念,什么是重入锁呢?也就说当一个线程当前已经申请到一个锁的时候,如果允许的代码里还有需要申请到该锁的情况,那么会直接拿到该锁,不需要进行排队等待。这里会涉及一个计数器概念,每次获取锁,计数器都会+1,释放锁,计数器-1,直到计数器为0为止,才能保证锁被彻底释放,别的线程才能够进行锁的申请。
详情可以参考这篇文章 https://www.cnblogs.com/Andya/p/7272276.html
下面讲一下悲观锁概念

悲观锁
synchronized其实就是典型的悲观锁,在这种思想认为每次数据的操作都是不安全的,都有可能触发线程并发的问题,所以每次都是保证自己独占本次数据操作,将数据锁定。它的事务要想更新,必须等以前的事务提交或者回滚解除锁,其实这种在大并发的时候是很降低效率的。 无锁很开心

为了提高数据的操作效率又引入乐观锁(无锁)概念。认为系统中的事务并发更新不会很频繁,即使冲突了也没事,大不了重新再来一次。它的基本思想就是每次提交一个事务更新时,我们想看看要修改的东西从上次读取以后有没有被其它事务修改过,如果修改过,那么更新就会失败。
乐观锁引入了CAS技术,什么是CAS技术呢?
CAS的全称是Compare And Swap 即比较交换,其算法核心思想如下
执行函数:CAS(V,E,N)
其包含3个参数

上一篇 下一篇

猜你喜欢

热点阅读