1. 关键字synchronized
取得的锁都是对象锁,而不是把一段代码或方法当作锁。
2. 关键字synchronized
拥有锁重入的功能
在使用synchronized时,当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁的
在一个synchronized方法/块内部调用本类的其他synchronized方法/块时,是永远可以得到锁的
public class Service {
synchronized public void service1() {
...
service2();
}
synchronized public void service2(){}
}
当存在父子类继承关系时,子类是完全可以通过可重入锁调用父类的同步方法的
3. 当一个线程执行的代码出现异常时,其所持有的锁会自动释放
4. synchronized 不会由父类继承给子类
5. synchronized 同步语句块
public void service() {
...
synchronized(x) {
...
}
...
}
用synchronized 声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个长时间任务,那么B线程则必须等待比较长的时间。
synchronized方法是对当前对象进行加锁,而synchronized代码块是对某一个对象进行加锁
可以把synchronized 只加在方法内需要同步的公共资源修改上,让其他不需要同步的代码块可以被多个线程同时执行,节约时间
synchronized的对象监视器不同,会异步调用。测试:
class SyncBlock {
private String anyString = new String();
public void a() {
try {
synchronized (anyString) {
System.out.println(Thread.currentThread().getName() + ":begin");
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName() + ":end");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized public void b() {
System.out.println(Thread.currentThread().getName() + ":begin");
System.out.println(anyString + "。");
System.out.println(Thread.currentThread().getName() + ":end");
}
}
public static void main(String[] args) throws InterruptedException {
SyncBlock syncBlock = new SyncBlock();
Thread t1 = new Thread() {
@Override
public void run() {
syncBlock.a();
}
};
Thread t2 = new Thread() {
@Override
public void run() {
syncBlock.b();
}
};
t1.start();
t2.start();
}
}
//Thread-1:begin
//Thread-2:begin
//。
//Thread-2:end
//Thread-1:end
6. 静态同步synchronized方法 与 synchronized(class)代码块
synchronized 加在静态方法上,是对当前的Class类进行持锁,sychronized(class)也是同样的效果
synchronized加在静态方法和非静态方法上,持有锁的对象是不同的,是异步调用
对Class类加锁可以对类的所有实例起作用,同一个类的不同实例对象间调用这类方法是同步的
7. 要避免调用双方互持有对方锁的情况,互相等待对方释放锁会出现死锁
8. 内部类与静态内部类
内部类中同步方法规则和普通类一样
静态内部类 测试:
public class OutClass {
static class InnerClass1{
public void method1(InnerClass2 class2) {
...
synchronized(class2) {
...
}
...
}
public void method2() {
...
}
}
static class InnerClass2{
public void method1() {
...
}
}
}
····························································
InnerClass1 in1;
InnerClass2 in2;
线程1 in1.method1(in2);
线程2 in1.method();
线程3 in2.method1();
//线程1和线程3同步,和线程2异步
9. 对于锁对象,只要对象不变,即使对象的属性改变,运行的结果还是同步的
10. volatile关键字
主要作用是使变量在多个线程间可见
它会强制从公共栈中取得变量的值,而不是从线程私有数据栈中取得变量的值
只能修饰变量
volatile不支持原子性:
- 对于volatile修饰的变量,JVM虚拟机只是保证从主内存加载到线程工作内存的值是最新的。在加载后这个值可能被其他线程改了,这时线程工作内存的值已经加载,不会变化了,也就是私有内存和公共内存中的变量不同步
原子类型可以在没有锁的情况下做到线程安全