1.JUC简述
在 Java 5.0 提供了 java.util.concurrent(简称JUC)包,在此包中增加了在并发编程中很常用的工具类,
用于定义类似于线程的自定义子系统,包括线程池,异步IO和轻量级任务框架;还提供了用于多线程上下文中的 Collection实现等。
2.valotile关键字
1>.禁止指令重排序:不让虚拟机自动优化操作步骤,例如创建对象,然后初始化,最后给引用地址。然后虚拟机为了优化,可能会
让后两步调换,然后再多线程操作的时候可能拿到地址,而没有进行初始化,就会产生空指针异常
单例懒汉设计模式中会使用到
2>.确保内存可见性
在多线程共享资源操作中,每个线程都会拿到一份内存放到缓冲区,线程可能会会对资源进行修改,这种修改只是
在缓冲区中操作,并未来得急刷新到硬盘上,然后其他线程在刷新到硬盘上就执行了操作,所以所得的结果不准确
使用volatile关键字就可以让Java虚拟机知道只是一个会被多线程操作的数据,然后虚拟机就会让他保证这个变量
的可见性。
3>.synchronized和volatile的区别:
(1)synchronized可以实现互斥性和内存可见性,不能禁止指令重排序。
(2)volatile可以实现内存可见性,禁止指令重排序,不能保证原子性(互斥性)。
3.i++的原子问题
i++:值加载到操作数栈,变量表中i自加1,出栈到局部变量表
++i:变量表中i自加1,值加载到操作数栈,出栈到局部变量表
4.怎么解决i++原子问题
原子变量: JDK1.5 以后, java.util.concurrent.atomic包下,提供了常用的原子变量;
原子变量中的值,使用volatile 修饰,保证了内存可见性;
使用原子变量AtomicInteger a=new AtomicInteger(1); a.incrementAndGet()//实现了i++操作
CAS(Compare-And-Swap) 算法保证数据的原子性;
5.CAS算法
CAS(Compare-And-Swap) 算法是硬件对于并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令,
用于管理对共享数据的并发访问;
CAS 是一种无锁的非阻塞算法(属于乐观锁)的实现;
CAS 包含了三个操作数:1.进行比较的旧预估值A 2.需要读写的内存值V 3.将写入的更新值B
当且仅当 A == V 时, V = B, 否则,将不做任何操作,并且这个比较交换过程属于原子操作;
6.Lock接口
synchronized的缺陷:
(1)获取锁的线程如果由于某种原因,不能及时释放锁(除非发生异常),其他线程只能等待
(2)使用同一个锁会进入同一个等待队列,所以需要唤醒所有线程
(3)无法实现读写锁操作
Lock可以控制多个等待队列
Lock lock=new ReentrantLock();
Condition conditionA=Lock.newCondition();
7.并发集合
为什么要使用并发集合?在集合中数据进行添加或者删除操作的时候会有一个操作数,在遍历集合的时候会对操作数
进行判断,如果操作数的值改变了则抛出一个ConcurrentModifyException并发修改异常。
CopyOnWriteArrayList:相当于线程安全的ArrayList,可以重复。把add()方法上锁,然后定义一个volatile的数组,然后每次进行添加时都会复制一份,对内存的消耗
比较大,是以内存换安全的一种集合
CopyOnWriteSet:相当于线程安全的HashSet,不能重复。
ConCurrentHashMap:JDK1.7之前采用分段锁的方式来存储,每段都是Hash表(数组+链表)写入数据和扩容锁定,读取共享
JDK1.8之后取消分段锁机制,采用CAS算法,无锁算法,由底层的硬件支持(哈希表=数组+链表+红黑树)
如果该位置没有数据直接放入,有数据会对头结点上锁,因为可能会进行扩容
ArrayBlockingQueue:可以实现生产者消费者问题
8.同步工具类
1>.CountDownLatch(countDown()和await())
闭锁可以延迟线程的进度直到其到达终止状态,闭锁可以用来确保某些活动直到其他活动都完成才能继续执行:count
(1)确保某个计算在其需要的所有资源都被初始化后才能继续执行。
(2)确保某个服务在其依赖的所有其他服务都已经启动之后才启动。
(3)等待直到某个操作所有参与者都执行完毕其他线程才能继续执行。
2>.CyclicBarrier(new CyclicBarrier(4,Runnale))await()
CyclicBarrier和CountDownLatch类似(屏障)表面意思理解为可循环使用的屏障,作用是让一组线程在到达一个屏障时被阻塞,等到最后一个线程到达屏障点,才会运行被拦截的线程继续运行。
(1)构造函数 CyclicBarrier(int parties) 屏障拦截的线程数量
(2)await() 调用该方法时表示线程已经到达屏障,随即阻塞
3>.Semaphore
Semaphore 是 synchronized 的加强版,作用是控制线程的并发数量。就这一点而言,单纯的synchronized 关键字是实现不了的。