线程状态及状态之间的转换如图:
线程安全问题
主要诱因:
- 存在共享数据(也叫临界资源).
- 存在多条线程共同操作这些共享数据.
解决办法:
同一时刻有且仅有一个线程在操作共享数据,其他线程必须等到该线程处理完数据后再对共享数据进行操作.
此时便有了互斥锁.
互斥锁
该锁能达到互斥访问的目的,即当一个共享数据被当前正在操作的线程加上互斥锁之后,在同一时刻
,其他线程只能处于等待的状态,直到当前线程处理完释放该锁之后才有可能获得操作该共享数据的权利.
互斥锁的特性
- 互斥性: 即在同一时间内只允许一个线程持有某个对象锁,通过这种特性来实现多线程的协调机制,这样
在同一时间只有一个线程对需要同步的代码块进行访问
,互斥性也称为操作的原子性
. - 可见性: 必须确保锁在释放之前,对共享变量所做的修改,对于随后获取该锁的另一个线程是可见的(即在
获得锁时应获得最新的共享变量的值
),否则另一个线程可能是本地缓存的某个副本上继续操作,从而引起不一致.
synchronized关键字恰好满足了上面互斥锁的特性要求.
synchronized
synchronized锁的不是代码,锁的都是对象.
对象锁和类锁是互不干扰的.
根据获取的锁的分类:
- 获取对象锁.
- 获取类锁.
获取对象锁的两种方法
- 同步代码块(
synchronized(this)
,synchronized(类实例对象)
),其中的对象锁就是小括号里的 实例对象,在获取了这些对象锁之后我们再去执行花括号的内容. - 同步非静态方法(synchronized method),也就是以synchronized作为前缀的方法,此时对象锁就是当前对象的实例对象.
获取类锁的两种方法
- 同步代码块(synchronized(类.class)),其中锁就是小括号中的类的对象(Class对象).
- 同步静态方法(synchronized static method),其中锁是当前对象的类对象(Class对象).
对象锁和类锁的总结: