java中的锁
公平锁与非公平锁
公平锁:每个线程获取锁的机会是公平的,按照申请锁的顺序将线程放进一个FIFO队列中,谁先申请锁谁就先获取锁,每次有线程来抢占锁的时候,都会检查有没有等待队列,如果有,则将该线程加入等待队列
非公平锁:线程获取锁的机会是不公平的,获取锁的线程会随机抢占
synchronized实现的锁是一种非公平锁,公平锁可以通过ReentrantLock来实现,同时ReentrantLock也可以实现非公平锁
// 默认是非公平锁
Lock lock = new ReentrantLock();
//public ReentrantLock() {
// sync = new NonfairSync();
//}
// 公平锁
Lock lock = new ReentrantLock(true);
可重入锁
可重入锁指在同一个线程中外部方法持有的锁可以被内部方法获取
synchronized和ReentrantLock都是可以实现可重入锁
-
synchronized实现的可重入锁
public class TestReEntryLock {
public synchronized void set() {
System.out.println(Thread.currentThread().getName()+“set”);
get();
}public synchronized void get() { System.out.println(Thread.currentThread().getName()+"get"); set(); } public static void main(String[] args) { TestReEntryLock lock = new TestReEntryLock(); new Thread(()->{ lock.set(); },"t1").start(); }
}
-
ReentrantLock
public class TestReEntryLock {
Lock lock = new ReentrantLock(); public void set() { try { lock.lock(); System.out.println(Thread.currentThread().getName()+"\t set"); get(); } finally { lock.unlock(); } } public void get() { try { lock.lock(); System.out.println(Thread.currentThread().getName()+"\t get"); } finally { lock.unlock(); } } public static void main(String[] args) { TestReEntryLock lock = new TestReEntryLock(); new Thread(()->{ lock.set(); },"t1").start(); }
}
读写锁
支持共享读,不支持共享读写,和写。也就是说支持同时读,但是不支持同时写。这种锁可以提高读的并发性
public class WriteAndReadLock {
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
// 写操作
public void write() {
rwl.writeLock().lock();
System.out.println(Thread.currentThread().getName()+"正在写");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
rwl.writeLock().unlock();
System.out.println(Thread.currentThread().getName()+"写已经完成");
}
// 读操作
public void read() {
rwl.readLock().lock();
System.out.println(Thread.currentThread().getName()+"正在读");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"读已经完成");
rwl.readLock().unlock();
}
public static void main(String[] args) {
WriteAndReadLock wad = new WriteAndReadLock();
for (int i = 0; i < 3; i++) {
new Thread(()->{
wad.write();
}).start();
}
for (int i = 0; i < 3; i++) {
new Thread(()->{
wad.read();
}).start();
}
}
}
结果:
Thread-0正在写
Thread-0写已经完成
Thread-1正在写
Thread-1写已经完成
Thread-2正在写
Thread-2写已经完成
Thread-3正在读
Thread-4正在读
Thread-5正在读
Thread-3读已经完成
Thread-4读已经完成
Thread-5读已经完成
结论: 每个线程写操作不能被其它操作所打断,不支持共享写。读操作支持共享读
自旋锁
自旋锁在没有获取到锁的情况下不会马上将线程阻塞,而是不断尝试获取锁
public class RoteBySelf {
private AtomicReference<Thread> ar = new AtomicReference<Thread>();
// 手写一个自旋锁
public void lock() {
Thread thread = Thread.currentThread();
System.out.println(thread.getName()+"\t 尝试获取锁");
// 如果是第一次则获取锁成功,跳出while循环
while(!ar.compareAndSet(null,thread)) {
}
System.out.println(thread.getName()+"\t 获取锁成功");
}
public void unlock() {
Thread thread = Thread.currentThread();
ar.compareAndSet(thread, null);
System.out.println(thread.getName()+"\t 释放锁成功");
}
}
死锁
死锁是多个线程争抢共享资源导致互相等待的一种状态,如果没有外力驱使,那么该状态会一直存在。
产生死锁的条件:
- 互斥:一个资源要么被抢占,要么可用,必须是临界资源
- 请求和保持:线程请求到资源后,继续申请资源,并且保持原来所持有的资源
- 不可抢占:已经被分配的资源不可被抢占
- 环路等待:线程之间互相等待对方释放所持有的资源
public class DeadDemo implements Runnable{
private Account from;
private Account to;
private int amount;
public DeadDemo(Account from, Account to, int amount) {
this.from = from;
this.to = to;
this.amount = amount;
}
public void run() {
synchronized(from) {
synchronized (to) {
from.amount = from.amount-amount;
to.amount = to.amount+10;
System.out.println("success");
}
}
}
public static void main(String[] args) {
Account a1 = new Account();
Account a2 = new Account();
new Thread(new DeadDemo(a1,a2,10)).start();
new Thread(new DeadDemo(a2,a1,10)).start();
}
}
class Account{
int amount;
}
我的博客:java锁
上一篇: FastJson的忽略字段和格式日期用法
下一篇: Struts2框架入门