一 java-锁 目的
目的:防止多线程执行某段代码时导致的数据异常,互相干扰,所以把某段代码块加上锁,保证其原子性
二 使用 synchronized (java语言内置锁)
2.11 单独使用于对象,使用对象锁
object object_lock = new object();
public void run()
{
//被锁住的代码块,保证了原子性,同一时间只能被一个线程所操作
synchronized(object_lock){
do something;
}
}
Java中的每个对象都有一个监视器,来监测并发代码的重入,上面就synchronized获取了lock的监视器,
2.2 synchronized 用于方法,
public class Thread1 implements Runable{
public synchronized void run()
{
do something
}
}
其实是获取了Thread1的监视器,对象锁。
线程同步方法是通过锁来实现,每个对象都有且仅有一个锁,这个锁与一个特定的对象关联,线程一旦获取了对象锁,
其他访问该对象的线程就无法再访问该对象的其他同步方法。
三 java 显示锁
2.1 第一种显示锁 Lock
是语法层级的锁,
常用方法有
//获取锁
lock();
//释放锁
unlock();
//尝试获取锁
trylock();
Lock的实现为ReentrantLock()
使用范式为
//显示锁
Lock lock = new ReentrantLock();
//获取锁
lock.lock();
try {
//执行业务
} finally {
//释放锁
lock.unlock();
}
获取锁之后,一定要在finally中释放掉,
Lock与synchronized的比较
1 synchronized 代码简洁
2 Lock获取锁可以被中断,可以设置超时,可以尝试获取锁
如果业务场景满足2中这3点,可以考虑用Lock,否则就用synchronized。
2.2 第2种显示锁 读写锁 ReadWriteLock 接口
实现为 ReentrantReadWriteLock
概念:同一时刻允许多个线程同时访问,但是写线程访问的时候,所有线程都被阻塞
最适用于读多写少情况,比普通线程性能几何倍增加
用法:
//读写锁对象
ReadWriteLock myLock = new ReentrantReadWriteLock();
//读锁
Lock readLock = myLock.readLock();
//写锁
Lock writeLock = myLock.writeLock();
然后在多线程中,读的地方用读锁,写的地方用写锁即可。
2.3 Lock 里面的等待和通知
实现:
Lock lock = new ReentrantReadWriteLock();
Condition kmCondition = lock.newCondition();
kmCondition.await();//等待
kmCondition.signal();//通知
三 名次解释
3.1 可重入锁
就是可以被多次获取的锁
如
public synchronized void testA()
{
System.out.println("A方法执行业务");
testB();
}
public synchronized void testB()
{
System.out.println("B方法执行业务");
}
testA本身有一把锁,调用了testB()又一把锁,共2把锁,即多次获取了锁,叫重入锁。
public void lockTest() {
//获取锁
lock.lock();
try {
System.out.println("第一次获取了锁");
lock.lock();
try {
System.out.println("第二次获取了锁");
} finally {
//释放锁
lock.unlock();
}
} finally {
//释放锁
lock.unlock();
}
}
上面例子里,lock也可以获取2次锁,lock也是可重入锁
由此可见,synchronized 和Lock都属于可重入锁
3.2 公平锁和非公平锁
公平锁的概念:如果在时间上,先对锁进行获取的请求一定先被满足,这个锁就是公平锁(即先等先得),反之为非公平锁(随机给锁)
一般是Lock构造器默认的非公平锁,如果需要公平锁也可指定。
效率对比
非公平锁效率更高,为什么? 请看下面解释
时刻1 A线程 获取到了锁
时刻2 B线程此时也来请求拿锁 被阻塞,被操作系统挂起
时刻3 A线程执行完业务,释放了锁
时刻3 C线程也来请求锁
非公平锁工作机制
此时计算机把锁给C而不是给B
公平锁工作机制
此时计算机把锁给B而不是给A
但是此时B是挂起状态,所以首先要把线程B从挂起状态恢复为正常状态(这个过程会耗费较长的时间)
用非公平锁,把锁给C以后,C执行完业务后,可能刚好B从挂起状态恢复为正常(有这个概率),相对公平锁来说,就有机会减少唤醒挂起线程的这段时间,
所以我们说非公平说效率更高。
当然具体用哪种要根据业务,比如某些优先级高的业务,就想要优先执行,也可以用公平锁。