Java主要提供了3种实现多线程同步的机制:
(1)synchronized关键字
在Java语言中,每个对象都有一个对象锁与之相关联,该锁表明对象在任何时候只允许被一个线程所拥有,每当一个线程调用对象的一段synchronized代码时需要先获取这个锁,然后再执行相应的代码,执行结束后释放锁。
synchronized关键字主要有两种用法(synchronized块和synchronized方法),此外该关键字还可以作用于静态方法、类或某个实例。
(a)synchronized方法。在方法的声明前加入synchronized关键字,示例如下:
public synchronized void Test();
只要把多个线程对类需要被同步的资源放到Test()方法中,就能保证这个方法在同一时间只能被一个线程访问,从而保证了多线程访问的安全性。然而,当一个方法的方法体规模非常大时,该方法声明为synchronized会大大降低程序执行效率。为此,Java提供了synchronized块。
(b)synchronized块。synchronized块既可以把任意代码声明为synchronized,也可以指定上锁的对象,非常灵活。用法如下:
synchronized (synObject){
//访问synObject的代码
}
(2)wait()方法和notify()方法
当使用synchronized修饰某个共享资源时,如果线程1在执行synchronized代码,线程2也要执行同一对象的同一synchronized代码时,线程2要等线程1执行完成后才能继续执行。这种情况下可以使用wait()方法和notify()方法。
在synchronized代码被执行期间,线程可以调用对象的wait()方法,释放对象锁,进入等待状态,并且可以调用notify()方法或notifyAll()方法通知正在等待的其他线程。notify()方法仅唤醒一个线程(等待队列中的第一个线程)并允许它去获得锁,notifyAll()方法唤醒所有等待这个对象的线程并允许他们去获得锁(它们通过竞争的方式获得资源)
(3)Lock
JDK5新增加了Lock接口以及他的一个实现类ReentrantLock(重入锁),Lock也可以用来实现多线程的同步,方法如下:
(a)lock()。以阻塞的方式获得锁,即如果得到了锁立即返回;否则等待,知道获得锁返回。
(b)tryLock()。以非阻塞的方式获得锁,即如果得到立即返回true,否则立即返回false。
(c)tryLock(long timeout,TimeUnit unit)。如果获得锁,立即返回true,否则等待参数给定的时间单元,在等待过程中如果获得锁返回true,如果等待超时返回false。
(d)lockInterruptibly()。如果获得锁,立即返回,如果没有,当前线程处于休眠状态,直到获得锁,或者当前线程被别的线程中断(会受到InterruptedException异常)。与lock()的区别是,如果lock()方法获取不到锁,会一直处于阻塞,且会忽略Interrupt()方法。