美文网首页java技术
java线程之二(同步锁和通讯器)

java线程之二(同步锁和通讯器)

作者: 小可文志 | 来源:发表于2019-12-01 22:47 被阅读0次

目录:

一、Synchronized

二、volatile

三、CAS(CompareAndSwap)

四、LongAdder(分段锁累加器)

五、ReentrantLock(手动锁)

六、 ReentrantReadWriteLock(读写锁)

七、 countDownLatch(倒计时,门闩)

八、 CyclicBarrier(栅栏)

九、 Phaser

十、SemaPhore(信号灯)

十一、Exchanger(交换器)

十二、 LockSupport

十三、 AQS

十四、 ThreadLocal

--------------------------------------------------------------------正文分割线--------------------------------------------

一、Synchronized

1、Synchronized作用:

①同步性:保证在同一时刻,只有一个线程可以执行某个方法或某个代码块;

②可见性:保证共享对象被一个线程改变时,其他线程都立即可见。

2、Synchronized特点

①对象锁(静态方法的锁加在x.class对象上),本质是加在对象头的两位。

②互斥锁

③可重入锁:某个线程已经获得某个锁,可以再次获取锁(同步方法调锁住同一个对象的方法或者父类同步方法时)

④不公平锁:多个线程获取锁的顺序并不按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁

3、使用Synchronized可能出现的问题

①脏读:当写数据加锁,但是读数据不加锁;

②死锁:多个线程要访问的资源互相被占用造成程序无法进行下去的情况;

③锁的引用发生变化(所以用final修饰)导致锁无效;

④使用字符串或者基础类型数据作为锁(可能会死锁或不可知情况);

⑤线程中抛异常时会释放锁(所以需要try catch中小心处理异常);

4、Synchronized同步优化

①细化锁的颗粒度(针对锁住的代码块过多);

②粗化锁的颗粒度(针对代码块中多个地方加锁);

③使用Atomicxxx原子类(无锁优化CAS);

5、底层实现同步原理

在进入同步代码之前先获取锁,获取到锁之后锁的计数器+1,同步代码执行完锁的计数器-1,如果获取失败就阻塞式等待锁的释放。

同步方法通过ACC_SYNCHRONIZED标志,同步代码块是monitorenter和monitorexit指令操作。

6、Synchronized锁的四种状态和升级(单向升级,不可降级)

①无锁状态;

②偏向锁状态(第一个线程访问,只记录线程ID);

③轻量级锁状态(如果有线程争用则升级为轻量级锁,获取锁失败则进入自旋,旋转10次后升级为重量级锁,轻量级锁占用CPU);

④重量级锁(需要申请操作系统资源,但是不占用CPU,效率低)

7、底层实现可见性原理

JMM关于synchronized的两条规定:

1)线程解锁前,必须把共享变量的最新值刷新到主内存中

2)线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新获取最新的值。

8、自旋锁和重量级锁的适用情况

自旋锁:线程执行时间短,线程数少(Atomicxxx,各种Lock)

重量级锁:线程执行时间长,线程数多

二、volatile

1、volatile作用:

①可见性:保证共享对象被一个线程改变时,其他线程都立即可见(MESI:cpu缓存一致性协议);

②有序性:禁止指令重排序。

2、Volatile特点:

①效率比synchronised高;

②不能保证同步。

3、volatile如何保证有序性(禁止指令重排序)?

添加四个内存屏障

4、MESI缓存一致性协议?

CPU中每个缓存行(caceh line)使用4种状态进行标记(使用额外的两位(bit)表示):

M: 被修改(Modified)

该缓存行只被缓存在该CPU的缓存中,并且是被修改过的(dirty),即与主存中的数据不一致,该缓存行中的内存需要在未来的某个时间点(允许其它CPU读取请主存中相应内存之前)写回(write back)主存。

当被写回主存之后,该缓存行的状态会变成独享(exclusive)状态。

E: 独享的(Exclusive)

该缓存行只被缓存在该CPU的缓存中,它是未被修改过的(clean),与主存中数据一致。该状态可以在任何时刻当有其它CPU读取该内存时变成共享状态(shared)。

同样地,当CPU修改该缓存行中内容时,该状态可以变成Modified状态。

S: 共享的(Shared)

该状态意味着该缓存行可能被多个CPU缓存,并且各个缓存中的数据与主存数据一致(clean),当有一个CPU修改该缓存行中,其它CPU中该缓存行可以被作废(变成无效状态(Invalid))。

I: 无效的(Invalid)

该缓存是无效的(可能有其它CPU修改了该缓存行)。

5、可能出的问题

修饰引用类型时,引用指向的对象内容变化,volatile可能不起作用;

三、CAS(CompareAndSwap)

1、CAS内容:

CAS需要有3个操作数:内存地址V,旧的预期值old,即将要更新的目标值new。

CAS指令执行时,当且仅当内存地址V的值与预期值old相等时,将内存地址V的值修改为new,否则就什么都不做。并且Cpu保证整个比较并替换的操作是一个原子操作。

2、CAS缺点:

1)循环时间长开销很大。

2)只能保证一个共享变量的原子操作。

3)ABA问题(Java并发包为了解决这个问题,提供了一个带有标记的原子引用类“AtomicStampedReference”,它可以通过控制变量值的版本来保证CAS的正确性。,如果需要解决ABA问题,改用传统的互斥同步可能会比原子类更高效)。

四、LongAdder(分段锁累加器)

1、longAdder原理:

longAdder将value分散到一个数组中不同线程会命中到数组的不同槽中,各个线程只对自己槽中的那个值进行CAS操作。

2、longAdder性能:

longAdder在并发非常大时效率高于AtomicLong,但是也占用内存(以空间换时间)。

五、ReentrantLock(手动锁)

1、ReentrantLock作用:

手动给代码块加同步锁。

①可见性:保证共享对象被一个线程改变时,其他线程都立即可见(MESI:cpu缓存一致性协议);

②同步性;

2、ReentrantLock如何保证可见性

ReentrantLock的同步其实是委托给AbstractQueuedSynchronizer的。加锁和解锁是通过改变AbstractQueuedSynchronizer的state属性,这个属性是volatile的,volatile也能保证可见性

3、ReentrantLock与synchronised不同

①ReentrantLock必须手动加锁(lock())手动解锁(unlock);

②ReentrantLock可以尝试锁定;

③ReentrantLock可以指定公平锁和非公平锁(默认);

④ReentrantLock可以被interrupt打断

六、 ReentrantReadWriteLock(读写锁)

1、ReadWriteLock作用:

允许多个读线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。即写数据时使用排它锁,读锁可以在没有写锁的时候被多个线程同时持有(共享锁)。

2、使用场景:

假设你的程序中涉及到对一些共享资源的读和写操作,且写操作没有读操作那么频繁。

七、 countDownLatch(倒计时,门闩)

1、countDownLatch作用:

能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行(线程间通讯)。

2、主要方法:

Countdown()  await()

八、 CyclicBarrier(栅栏)

1、CyclicBarrier作用:

能阻塞一组线程直到指定的线程数必须同时到达栅栏位置,才能继续执行(线程间通讯)。

3、主要方法:

new CyclicBarrier(20, () -> System.out.println("。。。"))    await()

九、 Phaser

1、phoser作用:

控制多个线程分阶段共同完成任务(线程间通讯)。

十、*SemaPhore(信号灯)

1、semaPhore作用:

同一时刻允许多少个线程运行(线程间通讯)。

acquire(获取锁,阻塞方法,将信号数量减1)

release(释放灯信号,信号数量加1)

2、semaPhore场景:

限流

十一、Exchanger(交换器)

1、作用:用于两个工作线程之间交换数据(线程间通讯);

2、主要方法

①exchange(s)阻塞线程,等待另一个线程

3、场景:游戏中交换武器装备

十二、 LockSupport

1、作用:

 阻塞或者唤醒一个线程(线程间通讯)

2、主要方法

Park()  unpark()

3、特点

   ①无需加锁

②可精确唤醒某个线程

③unpark可于park之前执行;

十三、 AQS

AQS维护了一个volatile的state和一个线程队列

使用了varHandle--->>1普遍属性原子操作 2比反射快,直接操纵二进制码

十四、 ThreadLocal

线程独有的局部变量

原理:将对象放在了当前线程实例的Map<ThreadLocal,Object>中

场景:声明式事务,保证同一个Connection

相关文章

  • java线程之二(同步锁和通讯器)

    目录: 一、Synchronized 二、volatile 三、CAS(CompareAndSwap) 四、Lon...

  • Multi-Th:线程安全的一些基本概念

    线程安全基本概念 内置锁 每个Java对象都可以用作一个同步锁,这些锁被称为内置锁 或 监视器锁。线程在进入同步代...

  • Android中的多线程

    1. Java多线程基础 Java多线程,线程同步,线程通讯 2. Android常用线程 HandlerThre...

  • java-summery

    1、对象锁和类锁 java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁。线程进入同步代码...

  • Java 并发

    目录 (1)基础概念 (2)线程 (3)锁 (4)同步器 (5)并发容器和框架 (6)Java并发工具类 (7)原...

  • 2017 05 03 学习安排

    java7并发编程实战手册第4章以前的内容,包括线程同步方法、锁机制、线程执行器和fork&join框架 (图解算...

  • ReentrantLock和监视器锁的选择

    在Java多线程编程中,我们经常过加锁的机制来保证线程同步。以Synchronized关键字为实现方式的监视器锁和...

  • 十一 .Java并发工具

    Java中的锁 锁是一种线程同步机制,类似同步块,但是锁比Java的同步块更复杂。锁(以及其他更高级的同步机制)是...

  • Java并发编程(1):可重入内置锁

    每个Java对象都可以用做一个实现同步的锁,这些锁被称为内置锁或监视器锁。线程在进入同步代码块之前会自动获取锁,并...

  • Java并发编程(1):可重入内置锁

    每个Java对象都可以用做一个实现同步的锁,这些锁被称为内置锁或监视器锁。线程在进入同步代码块之前会自动获取锁,并...

网友评论

    本文标题:java线程之二(同步锁和通讯器)

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