synchronized
使用方式
1.修饰一个代码块,被修饰的代码块称为同步代码块,作用范围是{}里面的部分
2.修饰一个方法,被修饰的方法称为同步方法,作用范围是整个方法
3.修饰一个静态方法,作用范围是整个静态方法
4.修饰一个类,作用范围是synchronized后面括起来的部分
使用
1.修饰代码块
public void method(){
synchronized(this){
//this表示锁是当前对象,锁可以自定义,但要实现同步必须是同一把锁
}
}
2.修饰方法
public synchronized void method(){
}
a.接口方法不能使用synchronized
b.构造方法不能使用synchronized,但是可以使用代码块进行同步
c.synchronized关键字无法继承,在父类中使用synchronized的方法,在子类中覆盖这个方法,默认情况下并不是同步的
解决方案:子类方法加上synchronized;通过super调用父类的同步方法
3.修饰静态方法
public synchronized static void method(){
}
4.修饰类
class Test{
public void method(){
synchronized(Test.class){
}
}
}
代码块同步:
当两个并发线程访问同一个对象中加速的代码块时,只能有一个线程得到执行,另一个阻塞,等待执行完毕,才能开始执行
分别创建两个对象,那么会同时执行,因为锁只会锁住当前一个对象
修饰普通方法:
在方法前加上synchronized修饰
传入一个对象,执行到synchronized修饰的方法时,只有一个线程能执行,另一个阻塞,等待执行完毕,才开始执行
两个对象,两把锁,会同时执行
静态方法:
被synchronized修饰的静态方法,要靠类锁工作,当多线程访问被synchronized修饰的静态方法时,一旦某个进程抢到该类的类锁之后,其他进程只有排队
修饰类:
修饰类时,是给这个类加锁,无论new出多少个对象,都共用一把类锁
synchronized和lock的区别
1.synchronized是java内置的关键字,在jvm层面,Lock是个java类
2.synchronized无法获取锁的状态,Lock可以判断是否获取到锁
3.synchronized会自动释放锁,Lock需要手动在finally中释放,否则容易造成线程死锁
4.用synchronized关键字的两个线程,当线程1获得锁时,线程2等待,如果线程1阻塞,线程2会一直等待;而Lock锁不会一直等待,如果尝试获取不到锁,线程可以不用一直等待就直接结束
5.synchronized的锁可以重入,不可中断,非公平,而Lock锁,可以重入,可判断,可公平
6.Lock锁适合大量同步的代码的同步问题,synchronized锁适合少量的代码同步问题
Lock
上图,当一个线程执行完毕之后,第二个线程才开始执行
如上图,tryLock尝试获取锁,如果获取成功返回true,如果获取失败返回false
tryLock设置等待时长,第一个线程执行要5s,第二个线程等待了4s,任然没有没等到锁,所以第二个线程结束
如果让第一个线程执行时间短一点,将5s改成3s
第二个线程会在第一个线程执行完成之后,获取到锁,然后执行