Java并发编程

Java并发编程

(1)三种性质
可见性:一个线程对共享变量的修改,另一个线程能立刻看到。缓存可导致可见性问题
原子性:一个或多个CPU执行操作不被中断。线程切换可导致原子性问题
有序性:编译器优化可能导致指令顺序发生改变。编译器优化可能导致有序性问题。
(2)三个问题
安全性问题:线程安全
活跃性问题:死锁、活锁、饥饿
性能问题:
使用无锁结构:TLS线程 局部 存储,Copy-On- Write,乐观 锁;Java的原子类,Disruptor无锁队列
减少 锁的持有时间:让锁细粒度 。如ConcurrentHashmap;再如读写锁,读无锁写有锁

(3)volatile
C语言中的原意:禁用CPU缓存,从内存中读出和写入。Java语言的引申义:Java会将变量立刻写入内 存, 其他 线程 读取时 直接从 内存读(普通变量改变后,什么 时候写入内 存是不一定的)、禁止指令重排序。
解决问题:

保证可见性
保证有序性
不能保证原子性
一种轻量级的线程安全处理机制

(3)互斥锁sychronized

锁对象:非静态this,静态Class,括号Object参数
预防死锁:互斥:不能破坏占有且等待:同时申请所有资源不可抢占:sychronized解决不了,Lock可以解决循环等待:给资源设置id字段,每次都是按顺序申请锁
等待通知机制:wait、notify、notifyAll
重要说明
在JDK1.6之前,synchronized是重量级锁,效率低下
从JDK1.6开始,synchronized 做了很多优化,如偏向锁、轻量级锁、自旋锁、适应性自旋锁、锁消除、锁粗化等技术来减少锁操作的开销
synchronized 同步锁一共包含四种状态:无锁、偏向锁、轻量级锁、重量级锁,它会随着竞争情况逐渐升级。synchronized 同步锁可以升级但是不可以降级,目的是为了提高获取锁和释放锁的效率synchronized 修饰的代 码块 : 通过 反编 译.class文件 ,通过查 看字节码 可以得到:在代 码块 中使用的是 monitorenter 和 monitorexit 指令,其中 monitorenter 指令指向同步代码块的开始位置,monitorexit 指令指明同步代码块的结束位置synchronized 修 饰的 方 法 :查看 字节码 可 以 得 到 : 在 同 步 方 法 中 会 包含ACC _SYN CHRON IZED标记符。该 标记符指明了该方法是一个同步方法,从而执行相应的同步调用

(4)公平锁/非公平锁
公平锁是指多个线程按照申请锁的顺序来获取锁。
非公平 锁是指多个线程获取锁的顺序并不是按照申请锁的 顺序,有可能后申请 的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。对于Java ReentrantLock而言,通过 构造函 数指定该锁是否是公平 锁, 默认 是非公平锁。非公平锁的优点在于吞吐量比公平锁大。
对于synchronized而言,也是一种非公平 锁。由于其并不 像ReentrantLock是通过AQS的来实现线程调度,所以并没有任何办法使其变成公平锁。

(5)可重入锁
可重 入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层 方法会自动获取该锁。
对于JavaReentrantLock而言,他的名字 就可以看出是一个可重入锁, 其名字 是Reentrant Lock重新进入锁。
对于Synchronized而言,也是一个可重入锁。可重入锁的一个好处是可一定程度避免死锁。
特殊的是ReentrantRead WriteLock可重入读写锁:
读锁属于共享锁,写锁属于独占锁
一个线程持有读锁获取写锁时互斥
持有写获取读没问题
ReentrantRead WriteLock是Lock的另一种实现方式,ReentrantLock是一个排他 锁,同一时间只允许一个线程访问,而ReentrantRead WriteLock允许多个读线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。相对于排他锁,提高了并发性。在实际应用中,大部分 情况 下对共享数据(如缓存)的访问都是读操作 远多于写操作,这时ReentrantRead WriteLock能够提供比排他锁更好的并发性和吞吐量。

编程实现:

//创建重入读 写锁对象,其中可以引入参 数boolean用于  设定是否使用公平 锁,  默认非公平锁
private     static     final   ReentrantRead WriteLock     lock=newReentrantRead WriteLock();
lock.readLock().lock();//申请读锁
lock.readLock().unlock();//释放所拥有的  读锁,如果  没有拥有读锁,则释放时报异常
IllegalMonitorStateException

//申请获取写锁
lock.writeLock().lock();
//由于写锁属于独占锁,所以必须释放读锁后才能申请
lock.writeLock().unlock();
lock.getHoldCount():int //获取所拥有的锁个数

在一个线程中读锁和读锁、写锁和写锁不互斥----可重入的概念,在一个线程中持有读不能申请写,但是持有写可以申请读.

(6)独享锁/共享锁

独享锁是指该锁一次只能被一个线程所持有。共享锁是指该锁可被多个线程所持有。对于JavaReentrantLock是独享锁。但是对于Lock的另一个实现类Read WriteLock,其读锁是共享锁,其写锁是独享锁。

读锁的共享锁可保证并发读是非常高效的,多线程中读写\写读\写写的过程是互斥的。

独享锁与共享锁也是通过AQS来实现的,通过实现不同的方法,来实现独享或者共享。对于synchronized而言,当然是独享锁。

(7)乐观锁/悲观锁
乐观锁与悲观锁不是指具体的什么类型的锁,而是指看待并发同步的角度。
悲观 锁认为对于同一个数据的并发操作,一定是会发生修改的,哪怕没 有修改,也会认为修改。因此对于同一个数据的并发操作,悲观锁采取加锁的形式。悲观的认为,不加锁的并发操作一定会出问题。
乐观 锁则 认为对于同一个数据的并发操作,是不会发生修改的。在更新数据的时候,会采用尝试更新,不断重试的方式更新数据。乐观的认为,不加锁的并发操作是没有事情的。
-CA S
悲观 锁适合写操作非常多的场景 ,乐观 锁适合读操作 非常多的场景 ,不加锁会带来大量的性能提升。悲观锁在Java中的使用,就是利用各种锁。乐观 锁在Java中的使用,是无锁编程,常常采用的是CA S算法,典型 的例子就是原子类,通过CA S自旋实现原子操作的更新。

(8)偏向锁/轻量级锁/重量级锁

这三种锁是指锁的状态,并且是针对Synchronized。在Java 5通过引入锁升级的机制来实现高效Synchronized。这三种锁的状态是通过对象监视器在对象头中的字段来表明的。偏向锁是指一段同步代码一直被 一个线程所访问, 那么 该线程会自动 获取锁。降低 获取锁的代价。
轻量级锁是指当锁是偏向锁的时候,被另一个线程所访问, 偏向锁就会升级 为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能。
重量 级锁是指当锁为轻量级锁的时候,另一个线程虽然 是自旋 ,但 自旋 不会一直持续下去当自旋 一定次数的时候,还没 有获取到锁,就会进入阻塞 ,该锁膨胀 为重量级锁。重量级锁会让其他申请的线程进入阻塞,性能降低。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值