Java并发编程--3.Lock

java

它提供3个常用的锁

lock() : 获不到锁就就一直阻塞

trylock() :获不到锁就立刻放回 或者 定时的,轮询的获取锁

lockInterruptibly() : 获不到锁时阻塞,但可接受中断信号后退出阻塞状态

ReentrantLock

实现机制

基于冲突的乐观并发策略:

如果共享数据被争用,产生了冲突,那就再进行其他的补偿措施,比如说定时的获取锁,直到成功;不需要把线程挂起,也称为非阻塞的同步

公平性

公平: 多个线程在等待同一个锁时,必须按照申请锁的时间顺序排队等待
非公平: 在锁释放时,任何一个等待锁的线程都有机会获得锁,ReentrantLock构造方法,默然是非公平的

什么时候使用

当你需要可定时的和可中断的锁操作,公平队列,或者非块结构的锁,否则请使用synchronized

可中断的例子

public class MyReentrantLock {

private ReentrantLock lock = new ReentrantLock();

public void write() {

lock.lock();

try {

long startTime = System.currentTimeMillis();

System.out.println("开始往这个buff写入数据…");

for (;;)// 模拟要处理很长时间

{

if (System.currentTimeMillis() - startTime > Integer.MAX_VALUE) {

break;

}

}

System.out.println("终于写完了");

} finally {

lock.unlock();

}

}

public void read() throws InterruptedException {

lock.lockInterruptibly();// 注意这里,可以响应中断

try {

System.out.println("从这个buff读数据");

} finally {

lock.unlock();

}

}

public static void main(String args[]) {

MyReentrantLock buff = new MyReentrantLock();

final Writer2 writer = new Writer2(buff);

final Reader2 reader = new Reader2(buff);

writer.start();

reader.start();

new Thread(new Runnable() {

@Override

public void run() {

long start = System.currentTimeMillis();

for (;;) {

if (System.currentTimeMillis() - start > 5000) {

System.out.println("不等了,尝试中断");

reader.interrupt(); //此处中断读操作

break;

}

}

}

}).start();

}

}

class Reader2 extends Thread {

private MyReentrantLock buff;

public Reader2(MyReentrantLock buff) {

this.buff = buff;

}

@Override

public void run() {

try {

buff.read();//可以收到中断的异常,从而有效退出

} catch (InterruptedException e) {

System.out.println("我不读了");

}

System.out.println("读结束");

}

}

class Writer2 extends Thread {

private MyReentrantLock buff;

public Writer2(MyReentrantLock buff) {

this.buff = buff;

}

@Override

public void run() {

buff.write();

}

}

控制台输出:

开始往这个buff写入数据…

不等了,尝试中断

我不读了

读结束

ReentrantReadWriteLock读写锁

特点

互斥:它使得读写操作互斥,读读操作不互斥

锁降级:写线程获取写入锁后可以获取读取锁,然后释放写入锁,这样就从写入锁变成了读取锁

少写多读的例子

public class MyReadWriteLock {

public static void main(String[] args) {

PricesInfo pricesInfo = new PricesInfo();

Writer writer=new Writer(pricesInfo);

Reader read = new Reader(pricesInfo);

//写线程

Thread tw=new Thread(writer);

tw.start();

//多个读线程

for (int i=0; i<5; i++){

Thread tr=new Thread(read);

tr.start();

}

}

}

//读线程

class Reader implements Runnable{

private PricesInfo pricesInfo;

public Reader(PricesInfo pricesInfo){

this.pricesInfo = pricesInfo;

}

@Override

public void run() {

pricesInfo.getPrice();

}

}

//写线程

class Writer implements Runnable{

private PricesInfo pricesInfo;

public Writer(PricesInfo pricesInfo){

this.pricesInfo = pricesInfo;

}

@Override

public void run() {

pricesInfo.setPrice(Math.random()*10);

}

}

//数据实体

class PricesInfo {

private double price;

private ReadWriteLock lock = new ReentrantReadWriteLock();

public PricesInfo(){

}

//读锁

public void getPrice(){

lock.readLock().lock();

System.out.println(Thread.currentThread().getName()+ " : in read*****************************");

System.out.println(Thread.currentThread().getName()+ ": 读取数据= " + price);

lock.readLock().unlock();

}

//写锁

public void setPrice(double price){

lock.writeLock().lock();

try {

System.out.println(Thread.currentThread().getName()+ " :in Writer==============================================");

Thread.sleep(1000);

this.price = price;

System.out.println(Thread.currentThread().getName()+ ":写入数据= " + price);

} catch (InterruptedException e) {

e.printStackTrace();

}finally {

lock.writeLock().unlock();

}

}

}

控制台输出:

Thread-0 :in Writer==============================================

Thread-0:写入数据= 3.5843085966236266

Thread-3 : in read*****************************

Thread-3: 读取数据= 3.5843085966236266

......

 Condition条件变量

通过ReentrantLock的newCondition()得到Condition对象,它用await()替换wait(),用signal()替换 notify(),用signalAll()替换notifyAll(), 实现线程间的通信;

如果是公平锁,与Condition关联的任务,以FIFO的形式获取锁,否则的话,是随机获取锁;

消费者和生产者的例子

public class MyCondition{  

public static void main(String args[]){

Info info = new Info();

//启动生产者

Producer pro = new Producer(info) ;

new Thread(pro).start() ;

try{

Thread.sleep(100) ;

}catch(InterruptedException e){

e.printStackTrace() ;

}

//启动消费者

Consumer con = new Consumer(info) ;

new Thread(con).start() ;

}

}

class Info{ // 定义信息类

private String name = null;

private String content = null ;

private boolean flag = true ; // true生产, false消费

private Lock lock = new ReentrantLock();

private Condition condition = lock.newCondition(); //产生一个Condition对象

public void set(String name,String content){

lock.lock();

try{

while(!flag){

condition.await() ;

}

this.setName(name) ;

Thread.sleep(300) ;

this.setContent(content) ;

flag = false ; // 改变标志位,表示可以取走

System.out.println("生产者: " + this.getName() + " --> " + this.getContent()) ;

condition.signal();

}catch(InterruptedException e){

e.printStackTrace() ;

}finally{

lock.unlock();

}

}

public void get(){

lock.lock();

try{

while(flag){

condition.await() ;

}

Thread.sleep(300) ;

System.out.println("消费者: " + this.getName() + " --> " + this.getContent()) ;

flag = true ; // 改变标志位,表示可以生产

condition.signal();

}catch(InterruptedException e){

e.printStackTrace() ;

}finally{

lock.unlock();

}

}

public void setName(String name){

this.name = name ;

}

public void setContent(String content){

this.content = content ;

}

public String getName(){

return this.name ;

}

public String getContent(){

return this.content ;

}

}

/**生产者线程 */

class Producer implements Runnable{

private Info info = null ; // 保存Info引用

public Producer(Info info){

this.info = info ;

}

public void run(){

boolean flag = true ; // 定义标记位

for(int i=0;i<10;i++){

if(flag){

this.info.set("姓名--1","内容--1") ;

flag = false ;

}else{

this.info.set("姓名--2","内容--2") ;

flag = true ;

}

}

}

}

/**消费者线程 */

class Consumer implements Runnable{

private Info info = null ;

public Consumer(Info info){

this.info = info ;

}

public void run(){

for(int i=0;i<10;i++){

this.info.get() ;

}

}

}

AQS 和 CAS

AQS : JUC基础类

state : 获取锁的标志

NOde{} : 获取锁的线程
SHARED : 共享锁
EXCLUSIVE : 互斥锁

CLH同步队列

LockSupport.park() 和 LockSupport.unpark() :阻塞和唤醒

CAS: JUC基础理论

对内存中共享数据进行操作的指令集, 自动更新共享数据, 代替了锁

内存值V,旧的预期值A,要修改的新值B。当且仅A和内存值V相同时,将内存值V修改为B,否则什么都不做

ABA问题

因为CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A

以上是 Java并发编程--3.Lock 的全部内容, 来源链接: utcz.com/z/392619.html

回到顶部