Synchronized
- 概念:
重量级锁、重入锁、jvm 级别锁
使用:方法:ACC_SYNCHRONIZED、代码块 monitorenter\monitorexit
jvm 监视器 - 范围:方法和代码块(对象锁和类锁):
- 对于普通同步方法,锁是当前实例对象。 对于静态同步方法,锁是当前类的 Class 对象。 对于同步方法块,锁是 Synchonized
括号里配置的对象。
- 场景:
资源竞争
- Lock&ReentrantLock 写法:
try {
lock.lock();
} finally {
lock.unlock();
}
- void lock() 获取锁,调用该方法当前线程将会获取锁,当锁获取后,该方法将返回。
- void lockInterruptibly() throws InterruptedException 可中断获取锁,与 lock()方法不同之处在于该方
- ***响应中断,即在锁的获取过程中可以中断当前线程
- boolean tryLock() 尝试非阻塞的获取锁,调用该方法立即返回,true 表示获取到锁
- boolean tryLock(long time,TimeUnit unit) throws InterruptedException 超时获取锁,以下情况会返回:
- 时间内获取到了锁,时间内被中断,时间到了没有获取到锁。
- void unlock() 释放锁
-
统计:
java.util.concurrent.locks.ReentrantLock#getHoldCount
java.util.concurrent.locks.ReentrantLock#getQueuedThreads -
Synchronized 和 ReentrantLock 对比:
- Synchronized:jvm 层级的锁 自动加锁自动释放锁
- Lock:依赖特殊的 cpu 指令,代码实现、手动加锁和释放锁、Condition(生产消费模式)
- ReentrantReadWriteLock 读写锁
- 细粒度问题 ,读是共享的、写是独占的
- java8 增加了对读写锁的优化:StampedLock
- 实例代码
- static Lock可以锁注当前类 非静态的只能锁住当前类的实例对象
package com.itcode.锁;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/** * @author 夏天 * @date 2020年10月29日 22:32 */
public class ReentrantLock01 implements Runnable {
private static int i = 0;
static Lock lock = new ReentrantLock();
private void add() {
lock.lock();
try {
for (int i1 = 0; i1 < 5000; i1++) {
i++;
}
} finally {
lock.unlock();
}
}
@Override
public void run() {
add();
}
public static void main(String[] args) throws InterruptedException {
for (int j = 0; j < 20; j++) {
i = 0;
ReentrantLock01 sync01 = new ReentrantLock01();
ReentrantLock01 sync02 = new ReentrantLock01();
Thread t1 = new Thread(sync01);
Thread t2 = new Thread(sync02);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}
}
Lock之tryLock
使用方法:
try {
if(lock.tryLock());
} finally {
//获取到锁在释放 如果不加条件判断 获取不到锁也会进行释放 会抛出异常IllegalMonitorStateException
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
- tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。
- boolean tryLock(long timeout, TimeUnit unit) :
参数1 等待时间,参数2 时间单位
等待指定时间如果还获取不到锁返回false
实例代码:
package com.itcode.锁;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/** * @author 夏天 * @date 2020年10月29日 22:32 */
public class ReentrantLock02 implements Runnable {
private static int i = 0;
ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
try {
if (lock.tryLock(4, TimeUnit.SECONDS)) {
System.out.println(Thread.currentThread().getName() + "获取");
Thread.sleep(6000);
} else {
System.out.println(Thread.currentThread().getName() + "获取锁失败");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//注意 不加这个会报错 IllegalMonitorStateException 没有锁无法解锁
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
ReentrantLock02 reentrantLock02 = new ReentrantLock02();
Thread t1 = new Thread(reentrantLock02);
Thread t2 = new Thread(reentrantLock02);
t1.start();
t2.start();
t1.join();
t2.join();
}
}
ReentrantReadWriteLock 读写锁
细粒度问题 ,读是共享的、写是独占的
package com.itcode.锁;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/** * @author 夏天 * @date 2020年10月29日 22:42 * 可以同时读 上了写锁后就不可以读了 */
public class ReadWriterLockTest {
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();
ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
public String query() {
readLock.lock();
try {
Thread.sleep(50);
System.out.println("读数据");
return "成功";
} catch (InterruptedException e) {
e.printStackTrace();
return "成功";
} finally {
readLock.unlock();
}
}
public void save() {
writeLock.lock();
try {
System.out.println("保存数据");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
writeLock.unlock();
}
}
/** * 读50次 */
int readCount = 50;
/** * 写5次 */
int writeCount = 5;
public static void main(String[] args) throws InterruptedException, ExecutionException {
ReadWriterLockTest readWriterLockTest = new ReadWriterLockTest();
//new Thread(() -> {
// while (true) {
// readWriterLockTest.query();
// }
//}).start();
//new Thread(() -> {
// while (true) {
// try {
// readWriterLockTest.save();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
//}).start();
CompletableFuture<String> queryFuture = CompletableFuture.supplyAsync(() -> {
while (readWriterLockTest.readCount-- > 0) {
readWriterLockTest.query();
}
return "查询完成";
});
CompletableFuture<String> saveFuture = CompletableFuture.supplyAsync(() -> {
while (readWriterLockTest.writeCount-- > 0) {
readWriterLockTest.save();
}
return "保存完成";
});
//等待所有线程结束 无法接受返回值 ,接收返回值使用anyOf
CompletableFuture.allOf(queryFuture, saveFuture).get();
}
}