线程锁的问题

               

                                                                    锁对象是什么?

        锁对象指的是被锁的对象。注意这里的被字。

                                                                  

                                                                    使用锁的实质 

        多线程执行枷锁的方法或代码的时候,会先判断锁使用的锁是否被占用,如果没被占用就获取并使用该锁其他需要该锁的线程就处于等待状态;如果占用就需要等待该锁被释放重新尝试获取锁对象知道获取到锁对象才能执行后面的代码或方法。不应该把锁理解成锁,应该把它理解成一张通行证,有就可以继续走,没有就要等这张通行证。

这个是本质,要牢牢记下来;(理解下面的内容全靠这句话)

以后使用锁也要知道,锁对象是一切的关键。


                                                              使用锁的效果和怎么使用

          代码段级别的锁对象,是可以随意定义的,可以是当前对象,可以是当前类的其他实例对象,可以是当前类的字节码文件,可以是其他任意的引用对象。一旦锁住了锁对象,其他需要该锁对象的线程就必须等待。
  

          方法级别的同步锁(被synchronized修饰的方法),锁住的是当前对象。只要是使用该对象作为锁对象的代码都会产生互斥效果。

           该类中其他的synchronized方法在其他线程被该对象调用也是无法执行的,只能等待当前对象的释放。

其他以当前对象为锁的代码段,在其他线程是无法执行的也是要等。

          但是特别注意其他线程中该类的其他实例化对象调用synchronized方法是可以执行的,也就是说该方法锁不住其他实例化对象。因为其他对象调用同一个方法时枷锁的对象是调用该方法的对象this。如果想实现所有的对象中所有的线程中只能有一个该方法的调用,那么就在该方法的方法体内整个代码段加锁。

  
      类级别的同步锁(被synchronized修饰的静态方法),锁住的是当前类的字节码文件对象。如果该类有一个静态方法被synchronized修饰,那么多线程
中如果通过类调用该方法,那么只有一个线程中可以执行该方法,只有这个线程执行完这个方法,其他线程才可以

请求该方法。如果有其他类的代码使用当前类的class文件做锁对象,那么同样会产生互斥效果。


代码段使用class文件和synchronized静态方法会产生锁的竞争关系,产生互斥。

代码段使用当前对象做锁和synchronized方法会参数锁竞争关系,产生互斥。


                                                                       字符串锁

String 做为锁对象,在实际应用中是比较广泛和实用的。比如我要往数据库中并发修改一条数据,这时候需要并发修改实现串行化,我们可以使用该条数据的 id或其他唯一标识拼接一个 特殊含义的str 作为锁对象。

如果并发线程之间都是修改该条数据的id相同那么,这些线程间就会互斥,达到串行的效果,如果并发线程之间修改数据id不同那么因为锁对象不同,他们仍然可以并发执行互不干涉。这样即达到了同步的目的同时也,细粒化了同步操作,提高了效率。

但是在使用String 作为锁对象时可能会出现锁不住的问题。我们知道String 分String常量和String对象,如果用String常量作为锁的话,毫无疑问是可以实现同步效果的,因为String常量是唯一的,多个线程产生的String常量指向常量池中同一块区域。

但是如果用String 对象做为锁的话就可能出现锁不住的问题,因为多个线程产生的String 对象,并非同一个对象。不是同一个对象,就无法锁住。

而实际应用中,多个线程一般不会产生或者很难产生同一个字符串常量,一般都是产生多个字符串对象,这几个字符串对象的值相等,引用不相等。

所以为了能够解决这个矛盾,我们的思路是把字符串对象转化成字符串常量,这样就可以在多个线程中实现同步;

为了解决这个问题可以使用Goolge 提供的类库:

    Interner<String> pool = Interners.newWeakInterner();
    
    synchronized ( pool.intern( strLock ) ) {
    }
 

pool.intern( strLock ); 返回的是字符串对象在常量区的String,比如 String a = new String (“string”);

那么pool.intern( a )返回的就是“String”这个常量。

也就是说只要两个String对象通过equlas方法返回true,那么他们通过intern方法返回的就是同一个引用。同一个引用的话,就能够锁住了。

其实用jdk自带的str.intern 也是返回String在常量区的引用,也可以用做锁对象,但是这个方法有时候会出错,

所以还是建议使用Goolge提供的这个类来做比较好;

                                                                            同步锁原理

        同步锁判断是否同一个对象用的是 == 而非 equals,所以无论怎么用锁,首先想到 == ,尤其是Integer,String 这些既有常量也有对象的类。



                                                                     锁的本质(目的是串行化)

 使用同步锁实现互斥效果的本质是通过锁对象实现了代码的串行化,串行化的通道是获取锁对象然后上锁。

本质还是串行化。几乎所有解决线程安全问题的办法,归根到底都是进行串行化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值