为了解决竞争条件带来的问题,我们可以把资源锁起来。 多个线程共同读写的资源称为共享资源,也称为临界资源。 操作关键资源的代码区域称为关键节。 同时,进入临界区域的线程只有一个。 这称为排他锁。 这意味着不允许多个线程同时操作共享资源,同时只能由一个线程占用的锁称为Java多线程独占锁。
ReetranLock在java中实现了互斥,当访问同步资源时,该对象必须通过方法tryLock ) )获得该锁。 如果失败,则返回false;如果成功,则返回true。 根据返回的信息确定是否访问此同步的资源。 ReentrantLock互斥锁是一种可重新读取的锁,线程可以多次获得该锁。
在进入临界区之前,需要获得互斥锁。 如果有线程已经在使用资源,则必须等待其他线程返回独占锁。
操作共享资源(即退出关键节)后,必须返回独占锁,以便其他等待资源使用的线程可以进入关键节。
伪代码示例:
wait (锁定; //获取互斥锁
{
关键部分,使用共享资源
}
信号(lock ); //返回反弹锁定
在Java中,可以使用ReentrantLock锁定关键节,以防止多个线程同时进入关键节。
privatestaticlockbufferlock=newreentrantlock (;
publicstaticvoidprint (string msg ) {
bufferLock.lock (;
//操作临界区域、临界资源globalBuffer
bufferLock.unlock (;
}
在这里,只要在临界区前使用锁定(,在临界区后使用unlock )解除锁定即可。 java.util.concurrent实现了在临界区前判断锁定状态的任务,可以自己决定是屏蔽还是进入临界区。
已同步关键字
java为实现临界区域的互斥提供了更简单的方法。
例如,可以将synchronized关键字添加到使用共享资源的函数中。
publicsynchronizedvoidmyfunction (
//操作共享资源a
}
这样可以保证在同一时刻最多只有一个线程在执行函数。 如果资源a只在此函数中读写,则可以保证资源a不会同时读写多个线程。
但是,如果其他函数也操作共享资源a,则无法通过这种方式实现资源的独占使用。 即使所有这些函数都声明为synchronized,这也只是表明多个线程不能在同一时间执行同一函数,因为操作同一资源a的多个线程可以同时执行不同的函数。
以下是实现资源使用独占锁定的另一种方法。
同步代码块
通过声明函数同步,只能实现函数体的互斥。 通过将操作资源a的语句放入同步代码块中,可以确保资源同时只有一个线程可以使用资源,从而可以使用互斥资源。
公共语音函数1 () {
……
同步(a ) {
//操作资源a
}
……
}
公共语音函数2 () {
……
同步(a ) {
//操作资源a
}
……
}
这样,在同一时刻,资源a只能执行一个相应的同步代码块。 因此,无论在哪个位置使用资源a,多个线程都不会争用该资源。
通过ReentrantLock的构造函数可以看出,在实例化ReentrantLock时还可以实例化公平锁或不公平锁,但缺省情况下将构建不公平锁。 公平锁定与非公平锁定的区别在于竞争锁定时有无秩序。 Java多线程互斥锁ReentrantLock是通过继承接口Lock实现的,同样还有通过继承ReadWriteLock实现的ReentrantReadWriteLock。 这将在本站的Java多线程教程中详细讨论。