写点什么

并发编程专题四 - 原子操作和显示锁,java 面试刷题

用户头像
极客good
关注
发布于: 刚刚

自旋还是很消耗性能的


3、只能保证一个共享变量的原子操作


2.3、Jdk 中相关原子操作类的使用


更新基本类型类:AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference


更新数组类:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray


更新引用类型:AtomicReference,AtomicMarkableReference,AtomicStampedReference


原子更新字段类: AtomicReferenceFieldUpdater,AtomicIntegerFieldUpdater,AtomicLongFieldUpdater (较少使用)


代码示例:


import java.util.concurrent.atomic.AtomicStampedReference;


/**


  • @Auther: BlackKingW

  • @Date: 2019/4/15 22:09

  • @Description:带版本号的原子操作


*/


public class UseAtomicStampedReference {


static AtomicStampedReference<String> asr =


new AtomicStampedReference<>("BlackKingW",0);


public static void main(String[] args) throws InterruptedException {


final int oldStamp = asr.getStamp();//那初始的版本号


final String oldReferenc = asr.getReference();


System.out.println(oldReferenc+"==========="+oldStamp);


Thread rightStampThread = new Thread(new Runnable() {


@Override


public void run() {


System.out.println(Thread.currentThread().getName()


+"当前变量值:"+oldReferenc+"当前版本戳:"+oldStamp+"-"


+asr.compareAndSet(oldReferenc, oldReferenc+"Java",


oldStamp, oldStamp+1));


}


});


Thread errorStampThread = new Thread(new Runnable() {


@Override


public void run() {


String reference = asr.getReference();


System.out.println(Thread.currentThread().getName()


+"当前变量值:"+reference+"当前版本戳:"+asr.getStamp()+"-"


+asr.compareAndSet(reference, reference+"C",


oldStamp, oldStamp+1));


}


});


rightStampThread.start();


rightStampThread.join();


errorStampThread.start();


errorStampThread.join();


System.out.println(asr.getReference()+"==========="+asr.getStamp());


}


}


二、显式锁


=========

1、Lock****接口和核心方法

lock()? ?用来获取锁。如果锁已被其他线程获取,则进行等待。


unlock()?释放锁


tryLock()?它表示用来尝试获取锁,如果获取成功,则返回 true,如果获取失败(即锁已被其他线程获取


Lock 接口和 synchronized 的比较


synchronized:是 Java 语言内置关键字,不需要手动释放锁。代码简洁,


Lock:是实现的一个类,需要手动释放锁。并且获取锁可以被中断,拥有超时获取锁,尝试获取锁等机制。


代码示例:


import java.util.concurrent.locks.Lock;


import java.util.concurrent.locks.ReentrantLock;


/**


  • @Auther: BlackKingW

  • @Date: 2019/4/14 12:09

  • @Description:


*/


public class LockDemo {


private Lock lock = new ReentrantLock();


private int count;


public void increament() {


lock.lock();


try {


count++;


}finally {


lock.unlock();


}


}


public synchronized void incr2() {


count++;


incr2();


}


}


如 increament 采用 lock,代码相对复杂,并且使用 lock 一定要在 finally?中释放锁,否则可能会永远都释放不了,导致死锁。

2、可重入锁 ReentrantLock

可重入意思为:已经获得该锁的线程,可以再次进入被锁定的代码块。内部通过计数器实现。例如上面的代码


import java.util.concurrent.locks.Lock;


import java.util.concurrent.locks.ReentrantLock;


/**


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


  • @Auther: BlackKingW

  • @Date: 2019/4/15 22:09

  • @Description:


*/


public class ReentrantLockDemo {


private Lock lock = new ReentrantLock();


private int count;


public void increament() {


lock.lock();


try {


count++;


}finally {


lock.unlock();


}


}


public synchronized void incr2() {


count++;


incr2();


}


public synchronized void test3() {


incr2();


}


}


在增加一个方法 test3,去调用 incr2,如果该锁不可以被重入,则无法调用 incr2。导致程序一直运行不下去。可重入锁就是支持已经获取锁的线程,可以重复进入加锁的代码块。

3、公平锁和非公平锁。

公平锁非公平锁何谓公平性,是针对获取锁而言的,如果一个锁是公平的,那么锁的获取顺序就应该符合请求上的绝对时间顺序,满足 FIFO


当多个线程去请求加锁代码块时,同时只能有一个线程拥有锁,那么其他线程如果是按照到来的先后顺序,那么这个锁就是公平锁。比如 ReentrantLock 可指定是否为公平和非公平锁。否则就是非公平锁。比如 synchronized。


公平锁 VS 非公平锁


公平锁每次获取到锁为同步队列中的第一个节点,保证请求资源时间上的绝对顺序,而非公平锁有可能刚释放锁的线程下次继续获取该锁,则有可能导致其他线程永远无法获取到锁,造成“饥饿”现象。


公平锁为了保证时间上的绝对顺序,需要频繁的上下文切换,而非公平锁会降低一定的上下文切换,降低性能开销。因此,ReentrantLock 默认选择的是非公平锁,则是为了减少一部分上下文切换,保证了系统更大的吞吐量。

4、ReadWriteLock****接口和读写锁 ReentrantReadWriteLock

那是不是所有的锁都只能被一个线程所拥有呢?当然不是。例如 ReentrantReadWriteLock 读写锁。


ReentrantReadWriteLock 允许多个读线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。


ReadWriteLock 接口有两个方法


Lock readLock();? 获取读锁


Lock writeLock();? 获取写锁


ReentrantReadWriteLock 实现了 ReadWriteLock 接口。用于获取读写锁。


ReentrantLock 和 synchronized 关键字,同时只能有一个线程持有,所以都是排他锁,而 ReentrantReadWriteLock 可以同时有多个线程去访问,这种所也叫共享锁


使用场景: 读多写少的情况


代码示例


/**


  • @Auther: BlackKingW

  • @Date: 2019/4/15 22:09

  • @Description:


*/


public class UseSyn implements GoodsService {


private GoodsInfo goodsInfo;


public UseSyn(GoodsInfo goodsInfo) {


this.goodsInfo = goodsInfo;


}


@Override


public synchronized GoodsInfo getNum() {


SleepTools.ms(5);


return this.goodsInfo;


}


@Override


public synchronized void setNum(int number) {


SleepTools.ms(5);


goodsInfo.changeNumber(number);


}


}


import java.util.concurrent.locks.Lock;


import java.util.concurrent.locks.ReadWriteLock;


import java.util.concurrent.locks.ReentrantReadWriteLock;


/**


  • @Auther: BlackKingW

  • @Date: 2019/4/15 22:09

  • @Description:


*/


public class UseRwLock implements GoodsService {


private GoodsInfo goodsInfo;


private final ReadWriteLock lock = new ReentrantReadWriteLock();


private final Lock getLock = lock.readLock();//读锁


private final Lock setLock = lock.writeLock();//写锁


public UseRwLock(GoodsInfo goodsInfo) {


this.goodsInfo = goodsInfo;


}


@Override


public GoodsInfo getNum() {


getLock.lock();


try {


SleepTools.ms(5);


return this.goodsInfo;


}finally {


getLock.unlock();


}


}


@Override


public void setNum(int number) {


setLock.lock();


try {


SleepTools.ms(5);


goodsInfo.changeNumber(number);


}finally {


setLock.unlock();


}


}


}


/**


  • @Auther: BlackKingW

  • @Date: 2019/4/14 12:09

  • @Description:


*/


public interface GoodsService {


public GoodsInfo getNum();//获得商品的信息


public void setNum(int number);//设置商品的数量


}


/**


  • @Auther: BlackKingW

  • @Date: 2019/4/15 22:09

  • @Description:


*/


public class GoodsInfo {


private final String name;


private double totalMoney;//总销售额


private int storeNumber;//库存数


public GoodsInfo(String name, int totalMoney, int storeNumber) {


this.name = name;


this.totalMoney = totalMoney;


this.storeNumber = storeNumber;


}


public double getTotalMoney() {


return totalMoney;


}


public int getStoreNumber() {


return storeNumber;


}


public void changeNumber(int sellNumber){


this.totalMoney += sellNumber*25;


this.storeNumber -= sellNumber;


}


}


import java.util.Random;


import java.util.concurrent.CountDownLatch;


/**


  • @Auther: BlackKingW

  • @Date:2019/4/15 22:09

  • @Description:


*/


public class BusiApp {


static final int readWriteRatio = 10;//读写线程的比例


static final int minthreadCount = 3;//最少线程数


//static CountDownLatch latch= new CountDownLatch(1);


//读操作


private static class GetThread implements Runnable{


private GoodsService goodsService;


public GetThread(GoodsService goodsService) {


this.goodsService = goodsService;


}


@Override


public void run() {


// try {


// latch.await();//让读写线程同时运行


// } catch (InterruptedException e) {


// }


long start = System.currentTimeMillis();


for(int i=0;i<100;i++){//操作 100 次


goodsService.getNum();


}


System.out.println(Thread.currentThread().getName()+"读取商品数据耗时:"


+(System.currentTimeMillis()-start)+"ms");


}


}


//写操做


private static class SetThread implements Runnable{


private GoodsService goodsService;


public SetThread(GoodsService goodsService) {


this.goodsService = goodsService;


}


@Override


public void run() {


// try {


// latch.await();//让读写线程同时运行


// } catch (InterruptedException e) {


// }


long start = System.currentTimeMillis();

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
并发编程专题四-原子操作和显示锁,java面试刷题