Java高级进阶

2019-08-16-Java中实现的锁的区别和简单实现

2019-07-30  本文已影响0人  王元

Java中实现的锁的区别和实现的原理

在开发Java多线程应用程序中,各个线程之间由于要共享资源,必须用到锁机制。Java提供了多种多线程锁机制的实现方式,常见的有synchronized、ReentrantLock、Semaphore、AtomicInteger等。每种机制都有优缺点与各自的适用场景,必须熟练掌握他们的特点才能在Java多线程应用开发时得心应手。

一,synchronized

1,Java锁修饰的不同目标的区别,锁修饰对象有几种:

2,使用synchronized修饰的代码具有原子性和可见性,在需要进程同步的程序中使用的频率非常高,可以满足一般的进程同步要求

3,synchronized实现的机理依赖于软件层面上的JVM,因此其性能会随着Java版本的不断升级而提高。

4,当线程通过synchronized等待锁时是不能被Thread.interrupt()中断的,因此程序设计时必须检查确保合理,否则可能会造成线程死锁的尴尬境地。

5,尽管Java实现的锁机制有很多种,并且有些锁机制性能也比synchronized高,但还是强烈推荐在多线程应用程序中使用该关键字,因为实现方便,后续工作由JVM来完成,可靠性高。只有在确定锁机制是当前多线程程序的性能瓶颈时,才考虑使用其他机制,如ReentrantLock等。

二,ReentrantLock implements Lock

1,可重入锁,顾名思义,这个锁可以被线程多次重复进入进行获取操作。

代码实现如下

private final ReentrantLock lock = new ReentrantLock();
private void lock() {
    try {
        //设置为不响应中断锁
        //lock.lock();
        //设置为响应中断锁
        lock.lockInterruptibly();
        // do something
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        lock.unlock();
    }
}

2,线程在等待资源过程中需要中断

3,实现可轮询的锁请求

4,定时锁请求,基于3中提到的的lock.tryLock()方法

三,Semaphore 信号量

四,ReentrantReadWriteLock implements ReadWriteLock

除了Lock接口外,Java的API还提供了另一种读写分离锁,那就是ReadWriteLock。ReadWriteLock是JDK1.5后才引入的,作为读写分离锁,可以有效的帮助减少锁的竞争,提升系统性能。

用锁分离的机制来提升性能比较好理解

其实就是一句话,可以同时读,但是读写,写读,写写是互斥的

public interface ReadWriteLock {
    //读锁
    Lock readLock();
    //写锁
    Lock writeLock();
}

ReadWriteLock是一个接口,其使用的方式和Lock类似

内部都是使用AbstractQueuedSynchronizer即AQS算法来实现的,内部Sync,具体实现可以查看源码

五,StampedLock implements Serializable

StampedLock是java8中新增的类,它是一个更加高效的读写锁的实现,而且它不是基于AQS来实现的,它的内部自成一片逻辑,让我们一起来学习吧。

StampedLock具有三种模式:

代码实现分别如下:

private final StampedLock lock = new StampedLock();
private int x = 0;
private int y = 0;

/**
 * 写锁
 * @param moveX
 * @param moveY
 */
void tryWriteLock(int moveX, int moveY) {
    // 获取写锁,返回一个版本号(戳)
    long stampe = lock.tryWriteLock();
    x += moveX;
    y += moveY;
    //释放写锁,需要传入上面获取的版本号
    lock.unlockWrite(stampe);
}

/**
 * 乐观读
 */
Point tryOptimisticRead() {
    //乐观读锁
    long stampe = lock.tryOptimisticRead();
    int currentX = x;
    int currentY = y;
    //// 验证版本号是否有变化
    if(lock.validate(stampe)) {
        currentX = x;
        currentY = y;
    }
    lock.unlockRead(stampe);
    return new Point(currentX, currentY);
}

/**
 * 读锁
 */
Point tryReadLock(int newX, int newY) {
    //// 获取悲观读锁
    long stampe = lock.tryReadLock();

    while (x == 0 && y == 0) {
        // 转为写锁
        long ws = lock.tryConvertToWriteLock(stampe);
        if(ws != 0) {
            // 转换成功
            stampe = ws;
            x = newX;
            y = newY;
            break;
        } else {
            // 转换失败
            lock.unlockRead(stampe);
            // 获取写锁
            stampe = lock.writeLock();
        }
    }
    //释放锁
    lock.unlock(stampe);
    return new Point(x, y);
}

六,AtomicInteger

七,volatile关键字说明

volatile属于稍弱线程同步方式,但是AtomicInteger的实现又离不开volatile实现的机制,此处对volatile进行说明

上一篇下一篇

猜你喜欢

热点阅读