/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
/**
* Creates a new {@code ReentrantReadWriteLock} with
* the given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。如果在等待锁的期间调用了interrupt()方法,则会抛出InterruptedException。
static void test() {
final MyBlocingQueue<Integer> myBlocingQueue = new MyBlocingQueue(10);
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
exec.execute(() -> {
Random random = new Random();
int r = random.nextInt(100);
// 生成随机数,按照一定比率读取或者放入!
if (r < 30) {
myBlocingQueue.put(r);
} else {
myBlocingQueue.take();
}
});
}
exec.shutdown();
}
}
public interface ReadWriteLock {
/**
* Returns the lock used for reading.
*
* @return the lock used for reading.
*/
Lock readLock();
/**
* Returns the lock used for writing.
*
* @return the lock used for writing.
*/
Lock writeLock();
}
readLock()和writeLock()用来获取读锁和写锁,读锁是共享的(可以让多个线程同时持有,提高读的效率),而写锁是独享的。
基本规则:读读不互斥 读写互斥 写写互斥。
读写锁的实现原理(自己实现读写锁,方便理解):
public class ReadWriteLock {
/**
* 读锁持有个数
*/
private int readCount = 0;
/**
* 写锁持有个数
*/
private int writeCount = 0;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
// 设置新值,并返回旧值
public final int getAndSet(int newValue)
// 如果当前值为expect,则设置为u
public final boolean compareAndSet(int expect, int u)
// 当前值加1,返回旧值
public final int getAndIncrement()
// 当前值减1,返回旧值
public final int getAndDecrement()
// 当前值增加delta,返回旧值
public final int getAndAdd(int delta)
// 当前值加1,返回新值
public final int incrementAndGet()
// 当前值减1,返回新值
public final int decrementAndGet()
// 当前值增加delta,返回新值
public final int addAndGet(int delta)
源码实现:
// 封装了一个int对其加减
private volatile int value;
.......
public final boolean compareAndSet(int expect, int update) {
// 通过unsafe 基于CPU的CAS指令来实现, 可以认为无阻塞.
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
.......
public final int getAndIncrement() {
for (;;) {
// 当前值
int current = get();
// 预期值
int next = current + 1;
if (compareAndSet(current, next)) {
// 如果加成功了, 则返回当前值
return current;
}
// 如果加失败了, 说明其他线程已经修改了数据, 与期望不相符,
// 则继续无限循环, 直到成功. 这种乐观锁, 理论上只要等两三个时钟周期就可以设值成功
// 相比于直接通过synchronized独占锁的方式操作int, 要大大节约等待时间.
}
}
还是看下上章那个i++的例子,我们可以用synchronized和Lock来处理,也可以用无锁(乐观锁)的方式:
private static final class TestAtomic {
private AtomicInteger i = new AtomicInteger(0);
public void increase() {
i.incrementAndGet();
}
}
public static void main(String[] args) {
final TestAtomic testAtomic = new TestAtomic();
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
testAtomic.increase();
System.out.println(testAtomic.i.get());
}
}, "thread - " + i).start();
}
}
无论执行多少次,结果都是1-5(无重复)。
7.2 Unsafe
Unsafe类是在sun.misc包下,可以用于一些非安全的操作,比如:
根据偏移量设置值,线程park(),底层的CAS操作等等。
主要方法:
// 获得给定对象偏移量上的int值
public native int getInt(Object o, long offset);
// 设置给定对象偏移量上的int值
public native void putInt(Object o, long offset, int x);
// 获得字段在对象中的偏移量
public native long objectFieldOffset(Field f);
// 设置给定对象的int值,使用volatile语义
public native void putIntVolatile(Object o, long offset, int x);
// 获得给定对象对象的int值,使用volatile语义
public native int getIntVolatile(Object o, long offset);
// 和putIntVolatile()一样,但是它要求被操作字段就是volatile类型的
public native void putOrderedInt(Object o, long offset, int x);
7.3 AtomicIntegerFieldUpdater
这个类,我在看JDK源码中也经常看到,它的作用是让普通变量也享受原子操作。
先看个例子:
public static class TestAtomic {
// 如果直接把int改成AtomicInteger, 可能对代码破坏比较大
// 因此使用AtomicIntegerFieldUpdater对count进行封装
volatile int count;
}
// 通过反射实现
public final static AtomicIntegerFieldUpdater<TestAtomic> updater = AtomicIntegerFieldUpdater.newUpdater(TestAtomic.class, "count");
// 检查Updater是否工作正确, allCount的结果应该跟count一致
public static AtomicInteger allCount = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
final TestAtomic testAtomic = new TestAtomic();
Thread[] t = new Thread[1000];
for (int i = 0; i < 1000; i++) {
t = new Thread() {
public void run() {
if (Math.random() > 0.4) {
updater.incrementAndGet(testAtomic);
allCount.incrementAndGet();
}
}
};
t.start();
}
for (int i = 0; i < 1000; i++) {
t.join();
}
System.out.println("count=" + testAtomic.count);
System.out.println("allCount=" + allCount.get());
}
执行输出:count和allCount最终结果一致。