1 介绍synchronized

Synchronized是为了在一个资源(如一个方法就可以看出一个资源)上添加一个锁,保证在同一个时间点只有一个线程访问。

1.1 分类和作用范围

根据Synchronized作用范围,分为 类锁 和 实例对象锁 两种。

  • 类锁:把一个类的静态方法当做一个资源,在同一个时刻只有一个线程可以访问这个资源,此时需要使用类锁。
  • 实例锁:一个类实例化后的一个对象,把这个实例对象的一个方法当成一个资源,在同一个时刻只有一个线程可以访问这个资源,此时需要使用实例锁。

1.1.1 类锁

就是在静态方法的前面加上synchronized。

1.1.2 实例对象的锁

1. 非静态方法锁  synchronized method()

某线程执行print()方法,则该对象将加锁。其它线程将无法执行该对象的所有synchronized块。上面的代码等同 synchronized(this)这种方式

2. 指定类实例锁 synchronized(Object ob){ }

执行print(),会给对象a加锁,注意不是给Test的对象加锁,也就是说 Test对象的其它synchronized方法不会因为print()而被锁。同步代码块执行完,则释放对a的锁。

1.2 举例

问题:

那么,对于Something类的两个实例x与y,那么下列组方法何以被1个以上线程同时访问呢

  • x.isSyncA()与x.isSyncB()
  • x.isSyncA()与y.isSyncA()
  • x.cSyncA()与y.cSyncB()
  •  x.isSyncA()与Something.cSyncA()

答案:

  • 都是对同一个实例的synchronized域访问,因此不能被同时访问
  • 是针对不同实例的,因此可以同时被访问
  • 因为是static synchronized,所以不同实例之间仍然会被限制,相当于Something.isSyncA()与   Something.isSyncB()了,因此不能被同时访问。
  • 能够同时访问,因为一个是实例锁,一个是类锁

2 Synchronized(object)解析

执行结果为

3  wait和notify/notifyAll

何时释放锁?  两种情况:正常执行和wait–notify实现中途

3.1 Synchronized与wait/notify/notifyAll

总结1  调用wait()方法前的判断最好用while,而不用if;因为while可以实现被唤醒后线程再次作条件判断;而if则只能判断一次

总结2  有synchronized的地方不一定有wait,notify,但是有wait-notify的地方必须和Synchronized一块使用。即调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {…} 代码段内。

总结3 作用范围,synchronized的作用范围是一样,都是针对一个实例对象,而不是局限于某一个方法。

3.2 notify和notifyall理解

1. 相关类

(1)CountAddSub.java类

(2) Add1Runable类

(3) Add2Runable类

(4) SubRunnable.java

 (5) ThreadTest.java

执行结果为

2、notifyAll()方法

修改CountAddSub中的sub方法

执行结果为

4 问题

synchronized锁只有两个粒度,一个是类锁,一个是实例锁,而且临界区互斥量为1,对于有些需要临界区大于1的,那么synchronized就不够用了。得需要专门的信号量等机制了。

分类&标签