美文网首页工作生活
Synchronized&&volatile 学习

Synchronized&&volatile 学习

作者: 咩咩籽 | 来源:发表于2019-07-01 15:53 被阅读0次

    一般认为Synchronized锁定的是这段代码块,但事实上,Synchronized锁定的是当前对象。不仅如此Synchronized锁定的是heap内存中的这个对象而不是这个对象引用

    一般我们不使用字符串常量来作为锁对象,因为这样会使得线程莫名的阻塞。看起来是两个字符串的引用但是他们指向的是同一段的内存。例如有个lib的jar包,我们看不到源码,但是它方法种锁定了“hello”这个字符串,我们在自己的代码中也锁定了“hello”,效果就很美妙,进程会一直等待。

    关于线程安全:加synchronized关键字之后不一定能实现线程安全,具体还要看锁定的对象是否唯一。堆内存中的地址是否一样

    锁定的对象有两种情况:①类的实例 ②类的字节码(.class)

    synchronized关键字修饰普通方法等同于synchronized(this)

    synchronize关键字修饰静态方法锁定的是类的.class文件,静态方法中synchronize锁定代码块,锁定的对象不能是类的实例,只能是类的.class文件。原理如同在静态方法中不能直接调用非静态方法。类的.class文件是唯一的,所以说synchronize修饰静态方法或者锁定的对象是类的.class文件的时候,在多线程中是可以实现线程安全的

    1.同步方法和非同步方法是可以同时调用的

    2.对业务写方法加锁,同时也要对业务读方法加锁,否则容易产生脏读问题

    3.一个同步方法可以调用另一个同步方法,一个线程已经拥有某个对象的锁,再次申请的时候仍然会得到该对象的锁,也就是说synchronized获得的锁是可重入的(这里是继承中有可能发生的情形,子类调用父类的同步方法

    程序在执行过程中,如果出现异常,默认情况锁会被释放

    锁定某对象o,如果o的属性发生改变,不影响锁的使用

    但是如果o变成另外一个对象,则锁定的对象发生改变

    应该避免将锁定对象的引用变成另外一个对象

    1.业务逻辑中只有下面这句需要sync,这时不应该给整个方法上锁

    2.采用细粒度的锁,可以是线程争用时间变短,从而提高效率


    线程通信通常:一种是读取共享内存,还有一种就是线程之间互相通信。Java的线程采用的是读取共享内存。

    volatile 关键字,使一个变量在多个线程间可见

    A B线程都用到一个变量,java默认是A线程中保留一份copy,这样如果B线程修改了该变量,则A线程未必知道

    使用volatile关键字,会让所有线程都会读到变量的修改值

    使用volatile,将会强制所有线程都去堆内存中读取running的值

    volatile并不能保证多个线程共同修改running变量时所带来的不一致问题,也就是说volatile不能替代synchronized

    synchronize可以保证可见性和原子性,volatile只能保证可见性


    ++/--操作(其他操作)不是一个原子操作,所以在需要保证原子的++/--时可以通过上锁来解决问题,也可以通过

    AtomXXX类来解决问题 

    AtomXXX类本身方法都是原子性的,但不能保证多个方法连续调用是原子性

    AtomicInteger count = new AtomicInteger(0); 

    count.incrementAndGet(); //count++


    使用门闩机制

    使用Latch(门闩)替代wait notify来进行通知

    好处是通信方式简单,同时也可以指定等待时间

    使用await和countdown方法替代wait和notify

    CountDownLatch不涉及锁定,当count的值为零时当前线程继续运行

    当不涉及同步,只是涉及线程通信的时候,用synchronized + wait/notify就显得太重了

    这时应该考虑countdownlatch/cyclicbarrier/semaphore

    首先new一个门闩CountDownLatch latch = new CountDownLatch(1);

    里面有一个参数,同时他有一个方法就是latch.await();

    它会插在代码之间阻拦代码的执行。同时latch.countDown();

    方法会减少门闩的数量当门闩的数量减少为0的时候,这时门会自动打开,这时候latch.await();会向下执行。

    整个过程不涉及锁的机制,高效得实现了线程之间的通信。

    @author mashibing


    学习来自哔哩哔哩,马士兵老师高并发编程

    相关文章

      网友评论

        本文标题:Synchronized&&volatile 学习

        本文链接:https://www.haomeiwen.com/subject/lfbgcctx.html