synchronized:
JVM自带的一种锁,原理是字节码上通过monitorenter和monitorexit修饰
(1)是一个关键字,用于代码块的修饰,方法的修饰;
①修饰代码块:给指定对象加锁,进入代码块之前需要先获取该对象的锁;
// 修饰一个代码块,synchronized作用的对象为该类的对象实例
private void test1(int j) {
synchronized (this) {
for (int i = 0; i < loopNum; i++) {
log.info("test1 {} - {}", j, i);
}
}
}
// 修饰一个类,类锁锁的作用域是整个class。
// 无论创建多少实例,当其中某一实例调用类中此方法其他实例都要等待持有锁的实例释放锁后才会执行
private static void test1(int j) {
synchronized (SynchronizedExample2.class) {
for (int i = 0; i < loopNum; i++) {
log.info("test1 {} - {}", j, i);
}
}
}
②修饰普通实例方法:给当前类的对象加锁,进入同步代码前要获得当前对象实例的锁;
// 修饰一个方法
private synchronized void test2(int num) {
for (int i = 0; i < loopNum; i++) {
log.info("test2 {} - {}", num, i);
}
}
③修饰静态方法:也就是给当前类加锁,会作用于类的所有对象实例;(访问静态 synchronized 方法占用的锁是当前类的锁,而访问非静态 synchronized 方法占用的锁是当前实例对象锁。)
// 修饰一个静态方法
private static synchronized void test2(int j) {
for (int i = 0; i < loopNum; i++) {
log.info("test2 {} - {}", j, i);
}
}
(2)锁会自动释放,不会产生死锁;
(3)JDK6中synchronized加入了自适应自旋、锁消除、锁粗化、轻量级锁、偏向锁等一系列优化,在较少并发的情况下,效率高一些;
Lock:
Lock是JDK中的一个接口
(1)支持超时机制;
(2)锁需要手动unLock()释放;
try {
// ......
}catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
(3)ReentrantLock能够保证公平性(保证公平会降低一部分效率,需要判断有没有前节点);
// 参数:是否保证公平
ReentrantLock lock = new ReentrantLock(true);
(3)大量线程同时竞争,ReentrantLock要远胜于synchronized。