Java中同步机制可以用synchronized关键字来实现,当然了,其他办法也是有的。先从synchronized这个关键字说起吧。
首先synchronized关键字可以用来修饰对象的方法,对象的方法有静态方法与非静态方法;其次,synchronized可以修饰语句块。使用 synchronized关键字的语句块要先获得synchronized(something)中something所对应的锁,这个 something可能有很多种。
Java中的每个对象都对应一把锁,并且同时只能有一个线程获得该锁,如任何Object的实例或者其子类的实例都有唯一的锁。类似SomeClass.class的大家估计也经常用到,它也是Object的子类,也拥有唯一的锁。但是相同的线程可以多次获取同一对象的唯一锁。比如说在一个同步方法内调用了另一个同步方法的情况。对于每一把唯一锁都有一个计数器来表明当前锁被持有情况。进入同步方法或者同步块是计数器加1,退出时减1。
最普通的用法是:
- public synchronized void function(){//op}
此时执行此方法需要获得此方法所属的类的当前实例的锁,也就是说this变量所指代的对象的锁。所以上面的语句和以下语句是等效的:
- synchronized(this){//op}
假设function是SomeClass的一个方法,
- SomeClass sc = new SomeClass();
一般银行存取款 : 只有一个sc ,其他的sc1,sc2,sc3 ,都是不同的卡,所以互不影响 。
(生产者消费者问题,一般模拟的都是同一个生产者或者消费者的对象的多线程,其实现实中,多个生产者或消费者应该是不同的对象,银行取款是比较形象的)
还有就是synchronized修饰static方法:
- public synchronized static void function(){//op}
此时要执行该方法需要获得此方法所属的类SomeClass对应的SomeClass.class对象的锁。我们知道每个类如SomeClass对应的都有且只有一个SomeClass.class实例。此时多个线程执行此方法时,都要获得所属类的唯一关联实例SomeClass.class所对应的锁,所以无论何时都只有一个线程可以执行此方法。
在使用synchronized同步块时同同步方法基本一样的效果。同步普通的非静态实例时获得该实例所对应的锁,同步静态实例变量是同同步静态方法一样都需要获得其所属类对应的唯一SomeClass.class实例的锁,即类锁。
在程序中获取类锁 可以尝试用以下方式获取类锁 synchronized (xxx.class) {...} synchronized (Class.forName("xxx")) {...} 同时获取2类锁 同时获取类锁和对象锁是允许的,并不会产生任何问题,但使用类锁时一定要注意,一旦产生类锁的嵌套获取的话,就会产生死锁,因为每个class在内存中都只能生成一个Class实例对象。