lockInterruptibly 和lock的区别

本文深入探讨了并发编程中的线程执行顺序、锁机制及其使用方法,通过实例展示了如何在Java中正确处理线程同步问题,强调了ReentrantLock与synchronized关键字的区别,以及在不同场景下选择合适锁策略的重要性。

这是个被无数人写过并还会被其他人继续写下去的blog。

代码如下:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestLock {

	public static void main(String[] args) {
		Thread t1 = new Thread(new RunTt3());
		Thread t2 = new Thread(new RunTt3());
		
		t1.start();
		t2.start();
		t2.interrupt();
	}
}

class RunTt3 implements Runnable {

	private static Lock lock = new ReentrantLock();
	
	@Override
	public void run() {
		try {
			lock.lock();
			System.out.println(Thread.currentThread().getName() + " running");  
            TimeUnit.SECONDS.sleep(5);  
            System.out.println(Thread.currentThread().getName() + " finished"); 
		} catch(InterruptedException e) {
			System.out.println(Thread.currentThread().getName() + " interrupted");  
		} finally {
			lock.unlock();
		}
	}
}

 执行结果如下:

 

(1):

 

Thread-1 running
Thread-1 interrupted
Thread-0 running
Thread-0 finished

 (2):

 

 

Thread-0 running
Thread-0 finished
Thread-1 running
Thread-1 interrupted

 总结:
1、线程的执行是无序的,及线程的执行顺序不是按照线程的提交顺序来执行。上述代码中,t1的线程可以先执行;
2、使用显示式锁(ReentrantLock),一定要在finally代码块中释放锁;

 

 

当代码:

lock.lock();

 修改成:

lock.lockInterruptibly();

 执行结果如下:

Exception in thread "Thread-1" Thread-0 running
Thread-1 interrupted
java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:155)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1260)
	at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:460)
	at com.bohaisoft.concurrent.RunTt3.run(TestLock.java:33)
	at java.lang.Thread.run(Thread.java:745)
Thread-0 finished

 总结:

2、使用lockInterruptibly需要记住:当前线程可以被其他线程中止,并且在其他线程中抛出异常信息;
3、使用lock需要记住:当前线程也可以被其他线程中止,但不会抛出异常信息;

 

来自其他网站上的总结:

ReentrantLock获取锁定与三种方式:
a)lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁
b)tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;
c)tryLock(long timeout,TimeUnit unit),   如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;
d)lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断;

 

我的总结:

synchronized 与 Lock的区别主要表现在:
1、lock支持可判定是否能获取锁的操作,如果不能获取锁,则可以补尝处理,避免等待;
2、lock支持设置等待时间,避免无限制等待;
3、lock支持其他线程中止真在运行的线程;

### synchronized与Lock区别对比 #### 实现方式 `synchronized` 是 Java 内置的关键字,由 JVM 层面实现。它可以用于方法或代码块: ```java public synchronized void method() { // 同步方法体 } ``` 或者 ```java public void method() { synchronized(this) { // 同步代码块 } } ``` 而 `Lock` 是一个接口,位于 `java.util.concurrent.locks` 包中,需要通过编程方式手动获取释放锁[^3]。 #### 获取与释放锁 使用 `synchronized` 时,锁的获取释放是自动进行的,当线程进入同步代码块或方法时会自动获取锁,退出时会自动释放锁。这种方式简化了开发人员的工作,但也可能导致一些问题,例如死锁[^2]。 对于 `Lock` 接口,锁的获取释放必须显式地调用 `lock()` `unlock()` 方法来完成。这种灵活性允许更复杂的锁定模式,但也增加了出错的可能性。例如: ```java Lock lock = new ReentrantLock(); lock.lock(); try { // 执行临界区代码 } finally { lock.unlock(); // 必须在finally块中释放锁以确保异常情况下也能释放锁 } ``` #### 锁类型 默认情况下,`synchronized` 提供的是非公平锁,即多个线程竞争锁的时候,JVM 不保证哪个线程会获得锁。相比之下,`ReentrantLock` 允许选择是否为公平锁(通过构造函数参数指定)。如果希望线程按照请求顺序获得锁,则可以选择公平锁[^2]。 #### 可中断性 当线程试图获取由 `synchronized` 保护的资源时,如果该资源已被其他线程占用,那么这个线程将被阻塞直到锁可用。在此期间,线程不能响应中断。相反,`Lock` 接口提供了 `lockInterruptibly()` 方法,使得线程可以在等待锁的同时响应中断,这有助于避免死锁情况的发生[^4]。 #### 尝试获取锁 `synchronized` 没有提供尝试获取锁的功能;一旦开始等待,除非得到锁或者线程被中断(对于支持中断的情况),否则不会返回。然而,`Lock` 接口中的 `tryLock()` 方法可以让线程尝试一次或多次去获取锁,并且可以设置超时时间,这样即使在高并发环境下也能保持较好的性能[^2]。 #### 超时机制 与 `synchronized` 不同,`Lock` 支持超时机制。这意味着线程可以尝试在给定时间内获取锁,如果超过设定的时间仍未成功,则放弃此次尝试。这对于构建健壮的应用程序非常有用,因为它可以帮助防止无限期地等待锁的情况发生[^4]。 #### 条件变量 每个对象都隐含了一个与之关联的监视器,因此使用 `synchronized` 时只能有一个条件队列。但是,`ReentrantLock` 可以创建多个 `Condition` 对象,从而允许多个不同的条件与同一个锁相关联。这种方法提高了程序设计的灵活性,因为不同的条件可以独立处理而不互相影响[^4]。 #### 性能 早期版本的 Java (如 JDK 1.5) 中,由于 `synchronized` 是基于操作系统内核态的操作,所以它的效率相对较低。在这种情况下,推荐使用 `Lock` 接口以获得更好的性能表现。不过,在后续的 Java 版本中(比如 JDK 6 及以后),Oracle 对 `synchronized` 进行了大量的优化,包括引入偏向锁、轻量级锁等技术,使得其性能有了显著提升,接近甚至超越了 `Lock` 在某些场景下的表现[^1]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值