解决原子性
原子性问题的源头在于线程切换,我们用在32位cpu写long型数据为例
-
在单核时,写操作被分为两次,同一时刻只有一个线程执行,禁止cpu中断就禁止了线程切换,此时写操作具有原子性
-
多核情况下,同一时刻可能有两个线程执行,如果cpu禁止中断,只能保证线程不被切换,但是不能保证只有一个线程执行,如果两个线程都写long型的高32位,就会发生错误
-
同一时刻只有一个线程执行我们称为互斥,如果保证了互斥,就能保证保证原子性
-
保证互斥,首先想到了锁,需要互斥执行的代码称为临界区
-
java中的锁技术:synchornized,用不同的锁对受保护资源进行精细化的管理能提升性能,这种叫细粒度锁
-
死锁 活锁 饥饿
死锁:之前我们提到细粒度锁,它是提高并行度,是性能优化的重要手段,但是它的代价将是可能导致死锁,
死锁的定义:一组相互竞争资源的线程因互相等待,导致“永久”阻塞的现象
死锁发生的必备条件:
-
互斥,共享资源x和y只用被一个线程占有
-
占有且等待,线程t1已经取得x,等待y的时候不释放x
-
不可抢占,其他线程不能抢占线程t1的资源
-
循环等待
活锁:线程没有发生阻塞,但是仍然执行不下去
饥饿:线程因为无法访问所需要的资源而无法执行下去
解决饥饿的三种方案
-
保证资源充足
-
公平的分配资源(公平锁)
-
避免持有锁的时间过长
等待通知机制
synchronized 配合wait()notify()notifyAll()实现这种机制
wait与sleep的区别
-
sleep是Trhead方法,wait是Object方法,sleep必须指定时间
-
wait会释放锁,sleep不会
-
wait只能在同步代码块或者同步方法中使用
-
wait()方法与sleep()方法的不同之处在于,wait()方法会释放对象的“锁标志”。当调用某一对象的wait()方法后,会使当前线程暂停执行,并将当前线程放入对象等待池中,直到调用了notify()方法后,将从对象等待池中移出任意一个线程并放入锁标志等待池中,只有锁标志等待池中的线程可以获取锁标志,它们随时准备争夺锁的拥有权。当调用了某个对象的notifyAll()方法,会将对象等待池中的所有线程都移动到该对象的锁标志等待池。 sleep()方法需要指定等待的时间,它可以让当前正在执行的线程在指定的时间内暂停执行,进入阻塞状态,该方法既可以让其他同优先级或者高优先级的线程得到执行的机会,也可以让低优先级的线程得到执行机会。但是sleep()方法不会释放“锁标志”,也就是说如果有synchronized同步块,其他线程仍然不能访问共享数据
锁的性能问题以及解决
-
使用无锁的算法和数据结构,比如线程本地存储(ThreadLoca Storage,TLS),写入时复制(Copy-on-write)乐观锁 java并发包中的原子类Disruptor无锁的内存队列
-
减少锁持有的时间 例如细粒度锁(ConcurrentHashMap:使用分段锁)读写锁
加锁机制
竟态条件:指程序的执行结果依赖于线程执行的顺序
数据竞争:多个线程访问统一数据,且至少有一个线程写这个数据
1.内置锁 Java提供了一种内置的锁机制来达到原子性即同步代码块(Syncchronized).同步代码块包括锁的对象引用和这个锁保护的代码块。方法的同步代码块的锁就是调用的对象,静态的则是Class对象为锁。
2.重入 重入意味着获取锁的操作的粒度是“线程”,实现方法是为每一个锁关联一个获取技术值和一个所有者线程,当计数值为0时表明没有被持有,当线程请求持有锁时,jvm记录下持有者,计数值+1,如果同一个线程再次获取这个锁,计数值递增,当线程退出同步代码块时,相应的递减,为0时释放。
锁保护状态
-
对于可能被多个线程同时访问的可变状态变量,在访问它时都需要持有同一个锁,在这种情况下,称状态变量由锁保护。
-
对象的内置锁与其状态之间没有内在关联,当获取与对象关联的锁事,并不能阻止其他线程访问该对象,某个线程获取锁之后,只能阻止其他线程获取同一个锁,之所以每个对象都有内置锁,只是为了免去显示的创建锁对象。
-
对于每个包含多个变量的不变性条件,其中涉及的所有变量都需要用同一个锁来保护。
共享与发布对象
-
synchronized的两个属性 原子性和可见性,我们希望防止某个线程正在使用的对象状态而另一个对象同时修改,也希望一个线程修改了状态后,其他线程能够看到发生的状态变化。
-
在没有同步的情况下,编译器 处理器以及运行时等都可能对操作的执行顺序进行一些预想不到的调整。
-
只要有数据在多个线程之间共享,就使用正确的同步,否则会产生失效数据
volatile
-
声明为volatile变量,编译器与运行时都不会在内存上进行重排序,访问volatile变量不会加锁,因此不会发生线程阻塞,因此是比synchronized轻量级的同步机制
-
加锁机制确保可见性与原子性 ,volatile确保可见性
线程封闭
- Ad-hoc
- 栈封闭
- ThreadLocal类