1.Lock ()(不死不休)
2.boolean tryLock = lock.tryLock();子线程获取锁(浅尝辄止) 只要别人占用了锁 则就会获取锁失败
new Thread(new Runnable() {
public void run() {
//子线程获取锁(浅尝辄止)
boolean tryLock = lock.tryLock();
System.out.println("子线程获取锁:"+tryLock);
}
}).start();
3.lock.lockInterruptibly();//子线程获取锁(任人摆布) 只要线程被中止获取锁 响应中断
Thread thread = new Thread(new Runnable() {
public void run() {
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("this ask me to stop..");
}
}
});
thread.start();
Thread.sleep(7000);
thread.interrupt();
4.lock.unlock();//释放锁
5.Condition condition = new Condition();
object中的wait() notity,notityAll()只能和synchronized配合使用,可以唤醒一个或者全部(单个等侍集);
Condition需要与Lock配合使用的
a.condition.await();//将子线程挂起
b.condition.signal();//将线程释放
如果signal先于await执行是则会导致死锁现象。
注意点 condition前后都要加lock和unlock否则 报错。
代码如下:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 〈一句话功能简述〉<br>
* 〈Condition锁使用〉
*
* @author zhaohaiming
* @create 2019/9/28
* @since 1.0.0
*/
public class Test_Condition {
private static Lock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();
public static void main(String[] args) {
Thread thread = new Thread(){
@Override
public void run() {
lock.lock();
try {
System.out.println("here I am ....1");
try {
condition.await();//将子线程挂起
System.out.println("here I am ....2");
} catch (InterruptedException e) {
e.printStackTrace();
}
}finally {
lock.unlock();
}
}
};
thread.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.lock();
condition.signal();//将线程释放
lock.unlock();
}
}
结论:lock()最常用
2.lockInterruptibly()方法一般更昂贵,有的impl可能没有实现lockInterruputibly(),只有真的需要效应中断时,才使用,使用之前看impl对方法的描述。
二、ReentrantLock锁
lock与unlock一定要匹配使用
实现reentrantLock锁
代码如下:
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.LockSupport;
/**
* 〈一句话功能简述〉<br>
* 〈实现锁〉
*
* @author zhaohaiming
* @create 2019/9/30
* @since 1.0.0
*/
public class JameLock implements Lock {
//锁的拥有者
AtomicReference<Thread> owner = new AtomicReference<Thread>();
//记录重入次数
AtomicInteger count = new AtomicInteger(0);
//等待队列
private LinkedBlockingQueue<Thread> waiter = new LinkedBlockingQueue<Thread>();
public boolean tryLock() {
int ct = count.get();
//1.判断ct是否为0 如果为ct!=0 则说明锁被占用
if(ct != 0){
if(Thread.currentThread() == owner.get()){//如果是当前线程说明重入cout加1
count.set(ct+1);
return true;
}
}else {
//2.若ct=0时 说明锁被占 通过cas来抢锁
if(count.compareAndSet(ct,ct+1)){
owner.set(Thread.currentThread());
return true;
}
}
return false;
}
public void lock() {
//一定要拿到锁
if(!tryLock()){
//1.加入等待队列中
waiter.offer(Thread.currentThread());
for(;;){//自旋
//若线程是队列的头部尝试加锁
Thread head = waiter.peek();
if(head == Thread.currentThread()){
if(!tryLock()){//如果加锁没有成功则将线程挂起
//2.将当前线程进行阻塞 挂起
LockSupport.park();
}else {
//获取锁时 则把当前线程退出阻塞队列
waiter.poll();
return;
}
}else {
LockSupport.park();
}
}
}
}
public boolean tryUnlock() {
if(owner.get() != Thread.currentThread()){//如果不是当前线程获取释放锁则抛出异常
throw new IllegalMonitorStateException();
}else {
//unlock 是将count-1
int ct = count.get();
int nextc = ct -1;
count.set(nextc);
//如果nextc等于0 则释放锁成功
if(nextc == 0){
owner.compareAndSet(Thread.currentThread(),null);
return true;
}else {
return false;
}
}
}
public void unlock() {
if(tryLock()){
Thread head = waiter.peek();//获取队列头部线程
if(head != null){
LockSupport.unpark(head);
}
}
}
public void lockInterruptibly() throws InterruptedException {
}
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
public Condition newCondition() {
return null;
}
}
三、ReadWriteLock
1.概念:维护一对关联锁,一个只用于读操作,一个只用于写操作,读锁可以由多个读线程同时 持有,写锁是排他的,同一时间,两把锁不能衩不现线程持有
2.适合场景:适合读取 操作多于写操作的场景,改进互斥锁的性能。如果缓存件
3、锁降级:指的是写锁降级成为读锁,持有写锁的同时,再获取读取读锁,随后取读锁,随后释放写锁的过程
写锁是线程独占,读锁是共享:所以写->读是降级 (读到写 是不能实现的)
实现缓存存取数据
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 〈一句话功能简述〉<br>
* 〈模拟缓存〉
*
* @author zhaohaiming
* @create 2019/9/30
* @since 1.0.0
*/
public class CacheData {
/**
* 方法功能描述:
* 实现一个使用Cache数据的方法
* 如果缓存可用 就
* 如果缓存不可用,从DB加载数据到缓存 拿到数据之后,需要使用数据 这期间数据 不能发生改变
* @author zhaohaiming
* @date 2019/9/30 21:57
* @return
*@since: 1.0.0
*/
public static void main(String[] args) {
}
}
class TeacherInfoCache{
static volatile boolean cacheVale;
static final ReadWriteLock rwl = new ReentrantReadWriteLock();
static void processCacheData(String dataKey){
Object data = null;
rwl.readLock().lock();//先获取读锁
try {
if(cacheVale){//如果缓存可用 则从redis里取数据
data = Redis.data.get(dataKey);
}else {//从数据库里获取数据
//先把读锁释放重新获取写锁
rwl.readLock().unlock();
//为了避免大量并发访问数据库时 则加上写 只能一个线程访问数据库
rwl.writeLock().lock();
try {
if (!cacheVale){
DataBase.queryUserInfo();
Redis.data.put(dataKey,data);
cacheVale = true;
}else {
//锁降级 线程在占有写锁的时候,获取读锁
/***
* 锁降级 :指的是写锁降级成为读锁,持写写锁的同时,再获取读锁,随后释放写锁的过程。
*
* 写锁是线程独占共享, 所以写——》读是降级。(读——》写,是不能实现)
*/
rwl.readLock().lock();
data = Redis.data.get(dataKey);
}
}finally {
rwl.writeLock().unlock();
}
}
}finally {
rwl.readLock().unlock();//释放锁
}
}
}
class DataBase{
static String queryUserInfo(){
System.out.println("查询数据库。。。。");
return "name :Kody,age:40,gender:ture";
}
}
class Redis{
static Map<String,Object> data = new HashMap<String, Object>();
}