【剑指】synchronized与Lock的区别与使用?

711 阅读4分钟

synchronized和lock的区别使用这个问题大家不知道有没有碰到过,很多朋友看到这个问题,嘴巴能够巴兹两句,然后就哑火了,和面试官面面相觑,然后一首凉凉的bgm在耳边响起。下面就由shiyao酱为你来解答一下这个问题

1、线程与进程: 首先呢,咱们了解下线程和进程的知识,进程的范围比线程更大,拥有独立的资源分配调度。而线程是进程的小弟,没有办法,只能和其他线程共享资源(emmmm,小弟就是比较惨啊)

2、Thread的几个重要方法: 然后我们来了解一下thread的几个重要方法 start--------启动进程,内部其实是start方法运行之后会自动调用run方法 run---------启动之后,运行线程 stop--------强制结束线程 join------调用之后,得等待调用的方法结束,相当于插队

看到这里,可能有些人就会问啦,那wait()和notify()呢?要注意,其实wait()与notify()方法是Object的方法,不是Thread的方法!!同时,wait()与notify()会配合使用,分别表示线程挂起和线程恢复。

这里还有一个很常见的问题,顺带提一下:wait()与sleep()的区别,简单来说wait()会释放对象锁而sleep()不会释放对象锁。这些问题有很多的资料,不再赘述。

3、线程状态: 线程共有5大状态 新建--就绪---运行---阻塞---死亡

新建状态:新建线程对象,并没有调用start()方法之前

就绪状态:调用start()方法之后线程就进入就绪状态,但是并不是说只要调用start()方法线程就马上变为当前线程,在变为当前线程之前都是为就绪状态。值得一提的是,线程在睡眠和挂起中恢复的时候也会进入就绪状态哦。

运行状态:线程被设置为当前线程,开始执行run()方法。就是线程进入运行状态

阻塞状态:线程被暂停,比如说调用sleep()方法后线程就进入阻塞状态

死亡状态:线程执行结束

4、锁类型

可重入锁:在执行对象中所有同步方法不用再次获得锁

可中断锁:在等待获取锁过程中可中断

公平锁: 按等待获取锁的线程的等待时间进行获取,等待时间长的具有优先获取锁权利

非公平锁:随机获取锁

读写锁:对资源读取和写入的时候拆分为2部分处理,读的时候可以多线程一起读,写的时候必须同步地写

存在层次:synchronized是Java的关键字,在jvm层面上,Lock是一个类

锁的释放:synchronized以获取锁的线程执行完同步代码,释放锁 2、线程执行发生异常,jvm会让线程释放锁 lock在finally中必须释放锁,不然容易造成线程死锁

锁的获取:synchronized假设A线程获得锁,B线程等待。如果A线程阻塞,B线程会一直等待 Lock分情况而定,Lock有多个锁获取的方式,大致就是可以尝试获得锁,线程可以不用一直等待

锁类型:synchronized可重入 不可中断 非公平 Lock可重入 可判断 可公平(两者皆可)

适用范围:synchronized少量同步 Lock 大量同步

Lock详细介绍与Demo

public interface Lock {

/**
 * Acquires the lock.
 */
void lock();

/**
 * Acquires the lock unless the current thread is
 * {@linkplain Thread#interrupt interrupted}.
 */
void lockInterruptibly() throws InterruptedException;

/**
 * Acquires the lock only if it is free at the time of invocation.
 */
boolean tryLock();

/**
 * Acquires the lock if it is free within the given waiting time and the
 * current thread has not been {@linkplain Thread#interrupt interrupted}.
 */
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

/**
 * Releases the lock.
 */
void unlock();

} 从Lock接口中我们可以看到主要有个方法,这些方法的功能从注释中可以看出: lock():获取锁,如果锁被暂用则一直等待

unlock():释放锁

tryLock(): 注意返回类型是boolean,如果获取锁的时候锁被占用就返回false,否则返回true

tryLock(long time, TimeUnit unit):比起tryLock()就是给了一个时间期限,保证等待参数时间

lockInterruptibly():用该锁的获得方式,如果线程在获取锁的阶段进入了等待,那么可以中断此线程,先去做别的事

通过 以上的解释,大致可以解释在上个部分中“锁类型(lockInterruptibly())”,“锁状态(tryLock())”等问题,还有就是前面子所获取的过程我所写的“大致就是可以尝试获得锁,线程可以不会一直等待”用了“可以”的原因。

另外synchoronzied底层也做了很多优化

1、线程自旋和适应性自旋

2、锁消除

3、锁粗化

4、轻量级锁

5、偏向锁