Synchronized
两种用法:对象锁和类锁
一、对象锁
代码块形式:手动指定所对象
@Override
public void run() {
synchronized (this) {
System.out.println(Thread.currentThread().getName() + ":lock1已运行");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ":lock1执行结束");
}
}
锁对象的选择,默认为this,表示当前对象,面对复杂的业务逻辑,可能存在多个synchronized锁对象,就需要自己指定锁对象,两个锁之间是并行关系,不是串行关系
方法锁形式:Synchronized修饰普通方法,锁对象默认为this
@Override
public void run() {
method();
}
public synchronized void method() {
System.out.println("方法对象锁"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("方法对象锁结束"+Thread.currentThread().getName());
}
注:对象锁不适用不同的Runable实例
类锁
注:Java类可能有多个对象,但只有一个Class对象
所谓的类锁,就是Class对象的锁
类锁只能在同一时刻被一个对象拥有
与对象锁对比,适用于不同的Runable实例
Synchronized加在static方法上:适用于在全局控制锁
Synchronized(*.class)代码块
@Override
public void run() {
methods();
}
private void methods(){
synchronized (Synchroized2.class){
System.out.println("方法对象锁"+Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("方法对象锁结束"+Thread.currentThread().getName());
}
}
常见问题:
两个线程同时访问一个对象的同步方法(指被synchronized修饰的方法)
对象锁默认是this,所以线程一个一个执行,synchronized起作用
两个线程访问的是两个对象(特指实例)的同步方法
Synchronized不起作用,因为每个对象锁指的是各自的实例
两个线程访问的是synchronized的静态方法
静态方法是针对整个类的,所以synchronized起作用
同时访问同步方法和非同步方法
Synchronized只影响修饰的方法,对没有synchronized修饰的方法不影响
访问同一个对象的不同的普通同步方法
两个线程会串行执行,即两个方法被synchronized修饰,都会生效
同时访问静态synchronized和非静态synchronized方法
两个加的锁不是同一个锁,所以是并行
方法抛出异常后,会释放锁
线程的特性
可重入:同一线程的外层函数获得锁之后,内层函数可以直接再次获得该锁
好处:避免死锁。提升封装性
粒度:线程而非调用
不可中断:一旦这个锁被别人获得,我只能等待或者阻塞,直到别的线程释放这个锁;而lock类是拥有中断的这个能力,即可以中断获得锁的线程
Synchronized缺点
1.效率低:锁的释放情况少,试图获得锁时不能设定超时,不能中断一个试图获得锁的线程
2.无法知道是否成功的获取到了锁
3.不够灵活:读写锁相对来说更灵活 ;
建议使用lock
使用synchronized注意点:
锁对象不能为空,作用雨不宜过大,避免死锁