一、synchronized简介
synchronized是关键字,用来实现同步锁,非公平锁,可重入锁
公平锁:
是按照锁申请的顺序来获取锁,线程直接进入同步队列中排队,队列中的第一个线程才能获得到锁。
非公平锁:
非公平锁是线程申请锁时,直接尝试加锁,获取不到才会进入到同步队列排队。如果此时该线程刚好获取到了锁,那么它不需要因为队列中有其他线程在排队而阻塞,省去了CPU唤醒该线程的开销。而对于已经在同步队列中的线程,仍然是按照先进先出的公平规则获取锁~什么是可重入?
同一个线程可以反复获取锁多次,然后需要释放多次
它修饰的对象有以下几种:
1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
二、锁升级过程
二、ReentrantLock
ReentrantLock是一个可重入的同步锁,可以通过设置参数决定使用公平锁和非公平锁。
ReentrantLock lock = new ReentrantLock(); //参数默认false,不公平锁
ReentrantLock lock = new ReentrantLock(true); //公平锁
lock.lock(); //如果被其它资源锁定,会在此等待锁释放,达到暂停的效果
try {
//操作
} finally {
lock.unlock();
}
尝试等待执行:
ReentrantLock lock = new ReentrantLock(true); //公平锁
try {
if (lock.tryLock(5, TimeUnit.SECONDS)) {
//如果已经被lock,尝试等待5s,看是否可以获得锁,如果5s后仍然无法获得锁则返回false继续执行
try {
//操作
} finally {
lock.unlock();
}
}
} catch (InterruptedException e) {
e.printStackTrace(); //当前线程被中断时(interrupt),会抛InterruptedException
}
模拟三个线程:
使用ReentrantLock:
public class Test {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
new Thread(() -> {
System.out.println("A thread door");
lock.lock();
try{
System.out.println("-----A thread come in");
try {
TimeUnit.SECONDS.sleep(10);
System.out.println("=====A thread is over");
}catch (Exception e) {
e.printStackTrace();
}
}finally {
lock.unlock();
}
},"A").start();
new Thread(() -> {
System.out.println("B thread door");
lock.lock();//因为A线程已经占有了锁,所以会被阻塞在这一步
try{
System.out.println("-----B thread come in");
}finally {
lock.unlock();
}
},"B").start();
new Thread(() -> {
System.out.println("C thread door");
lock.lock();//因为A线程已经占有了锁,所以会被阻塞在这一步
try{
System.out.println("-----C thread come in");
}finally {
lock.unlock();
}
},"C").start();
}
}