sychronized与lock

一、 sychronized与lock的区别

  1. sychronized是java的关键字,而lock是一个类
  2. sychronized获取锁的时候,假设A线程获得锁,B线程等待,若A阻塞,B会一直等待;而lock在这种情况下B会尝试去获取锁
  3. sychronized的锁的状态是无法判断的,而lock是可以判断的
  4. sychronized与lock都是对象锁,都支持重入锁
  5. lock可以实现sychronized不具备的特性,如响应中断,支持超时,非阻塞的获取锁,公平锁,共享锁(读取锁)
  6. lock体系的Condition队列可以有多个(sychronized只有一个等待队列),可以进一步提高效率,减少线程阻塞带来的开销
    ReentrantLock实现了Lock接口
    ReentrantLock与Synchronized区别在于后者是JVM实现,前者是JDK实现,属于Java对象,使用的时候必须有明确的加锁(Lock)和解锁(Release)方法,否则可能会造成死锁。
    在这里插入图片描述

先来查看ReentrantLock的继承关系(下图),实现了Lock和Serializable接口,表明ReentrantLock对象是可序列化的。

二、 sychronized和ReentrantLock之间进行选择

与显式锁相比,内置锁仍然具有很大的优势。内置锁为许多优秀的开发人员所熟悉,并且简洁紧凑,而且在许多的程序中都已经使用了内置锁–如果将这两种机制混合使用,那么不仅容易令人困惑,也容易发生错误。ReentrantLock的危险性比同步机制要高,如果忘记在finally块中调用unlock,那么虽然代码表面上能正常运行,但实际上已经埋下了一颗定时炸弹,并且很可能伤及其他代码。仅当内置锁不能满足需求时,才考虑使用ReentrantLock。

 在一些内置锁无法满足需求的情况下,ReentrantLock可以作为一种高级工具。当需要一些高级功能时才应该使用ReentrantLock,这些功能包括:可定时的、可轮询的与可中断的锁获取操作,公平队列,以及非块结构的锁。否则,还是应该优先使用synchronized。

与ReentrantLock相比,内置锁的一个优点是:在线程转储中能给出在哪些调用帧中获得了哪些锁,并能够检测和识别发生死锁的线程。JVM并不知道哪些线程持有ReentrantLock,因此在调试使用ReentrantLock的线程的问题时,将起不到帮助作用。ReentrantLock的非块结构特性仍然意味着,获取锁的操作不能与特定的栈帧关联起来,而内置锁却可以。

未来更可能会提升synchronized而不是ReentrantLock的性能。因为synchronized是JVM的内置属性,它能执行一些优化,例如对线程封闭的锁对象的锁消除优化,通过增加锁的粒度来消除内置锁的同步,而如果通过基于类库的锁来实现这些功能,则可能性不大。

三、ReentrantLock的几个方法
lock():获得锁,如果锁已经被占用,则等待。
lockInterruptibly():获得锁,但是优先响应中断。
tryLock():尝试获得锁,如果成功返回true,失败返回false。该方法不等待,立即返回。
tryLock(long time,TimeUnit unit):在给定时间内尝试获得锁。
unLock():释放锁。

四、程序实例

  1. synchronized
    下面的例子是对former 和 latter 加入synchronized后,代码就可以实现线程之间的读写,避免former被别的线程改写后,另一个线程再执行int latter=sharedState;,避免出现former-latter!=1现象出现。
public class SynchronizedTest {
	public int sharedState;
	public void safeAction() {
		while (sharedState<100000) {
			
			// 给这块代码块加入同步锁
			synchronized (this) {
				int former=sharedState++;
				int latter=sharedState;
			
			
			if (former==latter-1) {
				
				System.out.println("Oberved data,former is "+former+" ,"
						+"latter is "+latter);
			}
		}}
	}
	public static void main(String[] args) throws InterruptedException{
		SynchronizedTest synchronizedTest=new SynchronizedTest();
		Thread threadA=new Thread() {public void run() {
			synchronizedTest.safeAction();
			
		}	
		
		};
		Thread threadB=new Thread() {public void run() {
			synchronizedTest.safeAction();
			
		}	
		
		};
		// 线程调用start方法,开启threadA线程
		threadA.start();
		//主线程调用join方法,获取对象threadA对象锁,挂起主线程.直到threadA线程结束
		threadA.join();
		// 线程调用start方法,开启threadB线程
		threadB.start();
		//主线程调用join方法,获取对象threadB对象锁,挂起主线程.直到threadB线程结束
		threadB.join();
}
	
}

  1. ReentrantLock
发布了45 篇原创文章 · 获赞 2 · 访问量 2563

猜你喜欢

转载自blog.csdn.net/u013915286/article/details/104011735