static long getRandomDelayModulusNanos(long timeout, TimeUnit unit) {
return DELAY_RANDOM;
}
static class DollarAmount implements Comparable {
public int compareTo(DollarAmount other) {
return 0;
}
DollarAmount(int dollars) {
}
}
class Account {
public Lock lock;
void debit(DollarAmount d) {
}
void credit(DollarAmount d) {
}
DollarAmount getBalance() {
return null;
}
}
class InsufficientFundsException extends Exception {
}
}
最典型的就是阻塞的有界队列的实现。
public class BoundedBuffer {
private static final Logger logger = LoggerFactory.getLogger(BoundedBuffer.class);
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[2]; // 阻塞队列
int putptr, takeptr, count;
private void log(String info) {
logger.info(Thread.currentThread().getName() + " - " + info);
}
public void put(Object x) throws InterruptedException {
log(x + “,执行put”);
lock.lock();
log(x + “,put lock.lock()”);
try {
while (count == items.length) { // 如果队列满了,notFull就一直等待
log(x + “,put notFull.await() 队列满了”);
notFull.await(); // 调用await的意思取反,及not notFull -> Full
}
items[putptr] = x; // 终于可以插入队列
if (++putptr == items.length) {
putptr = 0; // 如果下标到达数组边界,循环下标置为0
}
++count;
log(x + “,put成功 notEmpty.signal() 周知队列不为空了”);
notEmpty.signal(); // 唤醒notEmpty
} finally {
log(x + “,put lock.unlock()”);
lock.unlock();
}
}
public Object take() throws InterruptedException {
log(“执行take”);
lock.lock();
Object x = null;
log(“take lock.lock()”);
try {
while (count == 0) {
log(“take notEmpty.await() 队列为空等等”);
notEmpty.await();
}
x = items[takeptr];
if (++takeptr == items.length) {
takeptr = 0;
}
–count;
log(x + “,take成功 notFull.signal() 周知队列有剩余空间了”);
notFull.signal();
return x;
} finally {
lock.unlock();
log(x + “,take lock.unlock()”);
}
}
public static void main(String[] args) throws InterruptedException {
final BoundedBuffer bb = new BoundedBuffer();
ExecutorService executor = Executors.newFixedThreadPool(10);
for (char i = ‘A’; i < ‘F’; i++) {
final char t = i;
executor.execute(() -> {
try {
bb.put(t);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
List res = new LinkedList<>();
for (char i = ‘A’; i < ‘F’; i++) {
executor.execute(() -> {
try {
char c = (char) bb.take();
res.add©;
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
try {
executor.awaitTermination(2, TimeUnit.SECONDS);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
logger.info(res.toString());
executor.shutdownNow();
}
}
=======================================================================
Java5的时候J.U.C的ReentrantLock锁竞争性能非常好,到了Java6使用了改进后的算法来管理内置锁,所以现在差不太多了,只好一点点
竞争性能的影响可伸缩性的关键要素:如果有越多的资源被耗费在锁的管理和线程调度上,那么应用程序得到的资源就越少,锁的实现方式越好,将需要越少的系统调用和上下文切换。
====================================================================
ReentrantLock默认创建非公平的锁,非公平指被阻塞挂起的线程(LockSupport.park)都在AQS的CLH队列中排队等待自己被唤醒。他们是按照发出的请求顺序来排队的,但一旦有一个唤醒的就会和新来的线程竞争锁,新来的可能会“插队”。若新来的成功获取锁,那么它将跳过所有等待线程而开始执行,这意味着本该被唤醒的线程失败了,对不起您回到队列的尾部继续等。
一般,非公平锁的性能要好于公平锁。
因为一个线程被唤醒是需要时间的,挂起线程和唤醒恢复线程都存在开销,这个空隙如果有其他线程处于ready状态,无需上下文切换,那么直接运行就行。
A持有锁,B请求,但B在恢复的过程中,C可以插队"非公平"的获取锁,然后执行再释放,这时候B刚刚好做完上下文切换可以执行,这个对于B和C来说是一个“双赢”的局面,是提高吞吐量的原因。
JVM也没有在其内置锁上采用公平性的机制。
===================================================================
除非使用到3提到的高级特性,或者内置锁无法满足需求时,否则还是老实用内置锁,毕竟是JVM自身提供的,而不是靠类库,因此可能会执行一些优化。
另外内置锁在利用kill -3 dump thread的时候可以发现栈帧上的一些monitor lock的信息,识别死锁,而J.U.C的锁这方面就不太行,当然JAVA6之后提供了管理和调试接口解决了。
=====================================================================
ReentrantLock每次只有一个线程能持有锁,但是这种严格的互斥也会抑制并发。会抑制
-
写/写
-
写/读
-
读/读
冲突,但是很多情况下读操作是非常多的,如果放宽加锁的需求,允许多个读操作可以同时访问数据,那么就可以提升性能。
但是要保证读取的数据是最新的,不会有其他线程修改数据。
使用ReadWriteLock的场景:
-
一个资源可以被多个读操作访问
-
被一个写操作访问
-
但二者不能同时进行
如果读线程正在持有锁,这时候另外一个写线程,那么会优先获取写锁:
public class ReadWriteMap<K, V> {
private final Map<K, V> map;
private final ReadWriteLock lock=new ReentrantReadWriteLock();
private final Lock r=lock.readLock();
private final Lock w=lock.writeLock();
public ReadWriteMap(Map<K, V> map) {
this.map=map;
}
public V put(K key, V value) {
w.lock();
try {
return map.put( key, value );
} finally {
w.unlock();
}
}
public V remove(Object key) {
w.lock();
try {
return map.remove( key );
} finally {
w.unlock();
}
}
public void putAll(Map<? extends K, ? extends V> m) {
w.lock();
try {
总结
本文从基础到高级再到实战,由浅入深,把MySQL讲的清清楚楚,明明白白,这应该是我目前为止看到过最好的有关MySQL的学习笔记了,我相信如果你把这份笔记认真看完后,无论是工作中碰到的问题还是被面试官问到的问题都能迎刃而解!
MySQL50道高频面试题整理:
eturn map.put( key, value );
} finally {
w.unlock();
}
}
public V remove(Object key) {
w.lock();
try {
return map.remove( key );
} finally {
w.unlock();
}
}
public void putAll(Map<? extends K, ? extends V> m) {
w.lock();
try {
总结
本文从基础到高级再到实战,由浅入深,把MySQL讲的清清楚楚,明明白白,这应该是我目前为止看到过最好的有关MySQL的学习笔记了,我相信如果你把这份笔记认真看完后,无论是工作中碰到的问题还是被面试官问到的问题都能迎刃而解!
MySQL50道高频面试题整理:
[外链图片转存中…(img-yrS2rHep-1714524696253)]