11.5.2 互斥线程的设计方法
为了避免多个并行运行的线程对共享资源操作时可能出现的问题,Java语言引入了互斥锁。互斥锁是基于共享资源的互斥性设计的,用来标记那些多个并行运行的线程共享的资源。被互斥锁标记的共享资源,在一个时间段内,只能有一个线程使用;只有当加互斥锁的线程使用完了该共享资源,另一个线程才可以使用。这样就可以保证线程对共享资源操作的正确性。
在Java语言中,关键字synchronized就是用来给共享资源加互斥锁的。当某个共享资源被用synchronized修饰时,就表明该共享资源在某段时间内只能由加锁的线程访问。
为共享资源加互斥锁有两种方法:
(1)锁定一个对象和一段代码
声明格式为:
}
对象表示要锁定的共享资源,一对花括号内的语句组表示锁定对象期间执行的语句,或者说,表示对象的锁定范围。此格式可以用来在一个线程的一部分代码上加互斥锁。
当一个线程执行这段代码时,就锁定了指定的对象。此时,如果其他线程也要对加了互斥锁的对象进行操作,就无法进行;其他线程必须等候,直到该对象的锁被释放为止。加锁的线程执行完花括号内的语句后,将释放对该对象加的锁。这就形成了多个线程对同一个对象的“互斥”使用方式,因此该对象也称为互斥对象。
(2)锁定一个方法
声明格式为:
这里虽然没有指出锁定的对象,但是一个方法必然属于一个类,因此,此格式锁定的是该方法所属类的对象,锁定的范围是整个方法,即在一个线程执行整个方法期间对该方法所属类的对象加互斥锁。
当一个线程调用一个“互斥”方法时,它试图获得该方法锁。如果方法未锁定,则获得使用权,以独占方式运行方法体,运行完释放该方法的锁。如果方法被锁定,则该线程必须等待,直到方法锁被释放时。
【例11-6】带锁定的银行账户的存取款线程设计。
【设计思路】本例采用synchronized锁定一段代码的方式来解决多线程的并发执行问题。程序如下:
程序运行结果如下:
【程序说明】本例说明多个线程能够共享数据,但对同一数据进行操作时,出现并发执行问题,导致结果不正确。