java中锁的概念
- 自旋锁: 为了不放弃CPU执行事件,循环的使用CAS技术对数据尝试进行更新,直至成功。
- 悲观锁: 假定会发生并发冲突,同步所有对数据的相关操作,从读数据就开始上锁。
- 乐观锁: 假定没有冲突,在修改数据时如果发现数据和之前获取的不一致,则读最新数据,重试修改。
- 独享锁(写锁): 给资源加上写锁,线程可以修改资源,其他线程不能再加锁。
- 共享锁(读锁):给资源加上读锁后只能读不能改,其他线程也只能- - 加读锁,不能加写锁。
- 可重入锁/不可重入锁:线程拿到一把锁之后,是否可以自由进入同一把锁所同步的其他代码。
- 公平锁/非公平锁: 争抢锁的顺序,是否按先来后到。
synchronized
同步关键字synchronized,基于对象监视器实现。
java中的每个对象都与一个监视器相关联,一个线程可以锁定或解锁。
一次只有一个线程可以锁定监视器。
试图锁定该监视器的任何其他线程都会被阻塞,直到它们可以获得该监视器上的锁定为止。
特性: 可重入,独享,悲观锁
可重入示例:
// 可重入
public class SyncDemo {
public synchronized void test(Object arg) {
System.out.println(Thread.currentThread() + " 我开始执行 " + arg);
if (arg == null) {
test(new Object());
}
System.out.println(Thread.currentThread() + " 我执行结束" + arg);
}
public static void main(String[] args) throws InterruptedException {
new SyncDemo().test(null);
}
}
ReentrantLock
特点:独享锁;支持公平锁,非公平锁两种模式;可重入锁。
示例:
import java.util.concurrent.locks.ReentrantLock;
// 演示可重入
public class ReentrantDemo {
private static final ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
new Thread(()->{
lock.lock();
try {
System.out.println(Thread.currentThread()+"第一次获取锁");
System.out.println("当前锁的次数" + lock.getHoldCount());
Thread.sleep(500);
lock.lock();
System.out.println(Thread.currentThread()+"第二次获取锁");
System.out.println("当前锁的次数" + lock.getHoldCount());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("解锁");
lock.unlock();
lock.unlock();
}
System.out.println("当前锁的次数" + lock.getHoldCount());
}).start();
// 如果不释放,此时其他线程是拿不到锁的
new Thread(() -> {
System.out.println(Thread.currentThread() + " 期望抢到锁");
lock.lock();
System.out.println(Thread.currentThread() + " 线程拿到了锁");
}).start();
}
}
ReentrantReadWriteLock
维护一对关联锁,一个用于只读操作,一个用于写入;读锁可以由多个线程同时持有,写锁是排他的。即写锁线程独占,读锁共享。
锁降级是指写锁降级为读锁,在当前拥有写锁的同时,再获取到读锁,随后释放写锁的过程。
读写锁示例:
import java.util.concurrent.locks.ReentrantReadWriteLock;
// 读写锁(既保证了读数据的效率,也保证数据的一致性)
public class ReentrantReadWriteLockDemo {
ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public static void main(String[] args) {
final ReentrantReadWriteLockDemo readWriteLockDemo = new ReentrantReadWriteLockDemo();
// 多线程同时读/写
new Thread(() -> {
readWriteLockDemo.read(Thread.currentThread());
}).start();
new Thread(() -> {
readWriteLockDemo.read(Thread.currentThread());
}).start();
new Thread(() -> {
readWriteLockDemo.write(Thread.currentThread());
}).start();
}
// 多线程读,共享锁
public void read(Thread thread) {
readWriteLock.readLock().lock();
try {
int i = 5;
while (i>0) {
System.out.println(thread.getName() + "正在进行“读”操作");
i--;
}
System.out.println(thread.getName() + "“读”操作完毕");
} finally {
readWriteLock.readLock().unlock();
}
}
/**
* 写
*/
public void write(Thread thread) {
readWriteLock.writeLock().lock();
try {
int i = 5;
while (i>0) {
System.out.println(thread.getName() + "正在进行“写”操作");
i--;
}
System.out.println(thread.getName() + "“写”操作完毕");
} finally {
readWriteLock.writeLock().unlock();
}
}
}
读操作同时进行,所有读操作完毕后才能进行写操作。