线程安全问题的原因:
- 存在共享数据(也被称为临界资源)
- 存在多条线程共同操作这些数据的情况
解决方法:
在同一时刻,有且只有一个线程操作这些数据;其他线程必须等到这个线程,再对共享数据进行操作
互斥锁:
- 互斥性:在同一时间,只有一个线程,持有某个对象锁。通过这种特性,来实现多线程的协调机制。在同一时间,只有一个线程对需要同步的代码块进行访问。互斥性,也被称为操作的原子性
- 可见性:必须确保在锁被释放之前,对共享变量所做的修改,对于随后获得该锁的另一个线程是可见的(也就是,在获得锁时,应获得最新共享变量的值),否则另一个线程可能是在本地缓存的某个副本上继续操作,从而引起不一致。另一个锁在获取共享数据时,是最新的值
- synchronized 锁的是对象,不是代码
synchronized:
根据获取的锁的分类:获取对象锁 和 获取类锁
获取对象锁的两种用法:
- 同步代码块:synchronized (this):
- synchronized 类实例对象
- this,小括号中的就是实例对象
- 同步非静态方法: synchronized method:
- 锁时当前对象的实例对象
获取类锁的两种用法:(通过 对象锁实现的类锁)
-
- 同步代码块:synchronized (类.class):
- 锁是 ()小括号中的就是 类对象(class对象)
- 同步代码块:synchronized (类.class):
-
- 同步静态方法: synchronized static method:
- 锁时当前对象的类对象(class对象)
- 同步静态方法: synchronized static method:
对象锁和类锁的总结:
- 有线程访问对象的同步代码块时,另外的线程可以访问该对象的非同步代码块
- 若锁住的是同一个对象,一个线程在访问对象的同步代码块时,另一个访问的对象的同步代码块的线程被阻塞
- 若锁住的是同一个对象,一个线程在访问对象的同步方法时,另一个访问对象的同步方法的线程会被阻塞
- 若锁住的是同一个对象,一个线程在访问对象的同步代码块时,另一个访问对象同步方法的线程会被阻塞,反之亦然
- 同一个类的不同对象的对象锁互不干扰
- 类锁,由于也是一种特殊的对象锁,因此表现的同上述四点一致;而由于一个类只有一把对象锁,所以同一个类的不同对象使用类锁,将会是同步的
- 类锁和对象锁互不干扰
synchronized的底层原理:
monitor:每个Java对象都天生带着存在一个看不见的锁?