Java多线程之隐式锁&显式锁
在java编写多线程程序时,难免会遇到不同的线程需要同时操作同一个内存块的时候,这时如果不对操作进行锁约束来实现互斥,那么就有可能在同时操作时彼此之间相互影响,从而导致程序错误甚至崩溃。
java中锁的实现方式又可以分为隐式锁和显式锁,两者所实现的功能有重合的部分也有不同的部分,同时两者在使用方式上也有很大的区别。
显式锁
显式锁是通过java.util.concurrent.locks包中的Lock抽象类及其子类来实现的(主要是ReentrantLock子类)。使用方法是先创建出一个Lock对象,且保证需要互斥的多个线程使用同一个Lock对象。通过Lock对象的lock()和unlock()方法就能实现基本的加锁和解锁。
Lock l = new ReentrantLock();
l.lock(); //加锁
try{
++count_1; //这里编写需要互斥的操作
++count_2;
} finally {
l.unlock(); //解锁
}
同时显示锁支持公平锁模式,公平锁就是不同线程通过排队来得到锁的使用权,而非公平锁是谁先抢到锁,谁就拥有锁的使用权。当某个线程需要频繁使用锁对象时,非公平锁有可能导致其他线程一直等不到锁变量的释放。公平锁的使用只需要在构造方法传入true,表示使用公平锁。
Lock l = new ReentrantLock(true);
隐式锁
隐式锁是通过java的关键字synchronized来实现的,格式也比较简洁清晰,不用手动上锁和解锁,但相对来说就没有显示锁那么灵活,而且只支持非公平锁。
使用时可以用synchronized来修饰一个代码块,也可以用synchronized直接修饰一个方法。不同的线程在通过隐式锁进行互斥操作时,也需要一个全局对象作为锁变量。
对于代码块来说,这个全局对象需要手动给出
Object o = new Object(); //被指定的锁变量
sychronized(o) {
++count_1; //这里编写需要互斥的操作
++count_2;
}
对于非静态方法来说,锁变量默认为this,即方法的调用对象
class LockTest {
public int count_1;
public int count_2;
synchronized public void lockPlus() {
++count_1; //这里编写需要互斥的操作
++count_2;
}
synchronized public void lockReduce() {
--count_1; //这里编写需要互斥的操作
--count_2;
}
}
对于静态的同步方法来说,锁变量默认为该方法所在类的字节码文件,比如对于LockTest中的静态同步方法来说,锁变量就是LockTest.class。