Java multi-threaded high concurrency (1)--reentrant lock

reentrant lock

Why is it called reentrant lock? It is because the same thread can repeatedly enter the lock acquired by itself.

1. Features of reentrant locks

1.1 Reentrant lock is more flexible than synchronized, it can explicitly specify when to lock and when to unlock. (instance method lock(), unlock())

1.2 Interrupt response

Using the instance method lockInterruptibly() method of ReentrantLock (it is recommended to use a lock that can respond to interrupts), you can respond when the thread requests an interrupt to avoid waiting in the case of deadlock.

 

public class ReentrantLockInterruptDemo implements Runnable {
	public static ReentrantLock lock1 = new ReentrantLock();
	public static ReentrantLock lock2 = new ReentrantLock();
	int i;
	public ReentrantLockInterruptDemo(int i){
		this.i = i;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		try {
			if(i==1){
				//For lock requests, the lockInterruptibly method is used uniformly, which is a lock application action that can respond to interrupts. It can respond to interrupts while waiting for locks
				lock1.lockInterruptibly();
				try {
					Thread.sleep(500);
				} catch (Exception e) {
					// TODO: handle exception
				}
				lock2.lockInterruptibly();
			}else{
				//For lock requests, the lockInterruptibly method is used uniformly, which is a lock application action that can respond to interrupts. It can respond to interrupts while waiting for locks
				lock2.lockInterruptibly();
				try {
					Thread.sleep(500);
				} catch (Exception e) {
					// TODO: handle exception
				}
				lock1.lockInterruptibly();
			}
		} catch (InterruptedException e) {
			// TODO: handle exception
			e.printStackTrace ();
		}finally{
			if(lock1.isHeldByCurrentThread()){
				lock1.unlock();
			}else if(lock2.isHeldByCurrentThread()){
				lock2.unlock();
			}
			System.out.println(Thread.currentThread().getId()+":Thread exits");
		}
	}

	/**
	 * @param args
	 * @throws InterruptedException
	 */
	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		Thread t1 = new Thread(new ReentrantLockInterruptDemo(1));
		Thread t2 = new Thread(new ReentrantLockInterruptDemo(2));
		t1.start();
		t2.start();
		Thread.sleep(2000);
		t2.interrupt();
	}

}

 

1.3 Lock application waiting time limit

When applying for a lock (using the tryLock(timeout, unit) method), you can specify the waiting time. If the lock is not acquired within the specified time, return false, otherwise return true; and for the tryLock() method without parameters, the current thread will go to Attempt to acquire the lock, if the lock is occupied by another thread, it will return false immediately without causing the thread to wait.

 

public class ReentrantLockTryLockDemo implements Runnable {
	public static ReentrantLock lock = new ReentrantLock();
	
	@Override
	public void run() {
		try {
			System.out.println("I am in, I want to acquire the lock, I am _"+Thread.currentThread().getName());
			if(lock.tryLock(5, TimeUnit.SECONDS)){
				System.out.println("Who came in? I'm _"+Thread.currentThread().getName());
				Thread.sleep(6000);
			}else{
				System.out.println("I didn't get the lock, I left_"+Thread.currentThread().getName());
			}
		} catch (Exception e) {
			e.printStackTrace ();
		}finally{
			if(lock.isHeldByCurrentThread()){
				lock.unlock();
			}
		}
	}

	/**
	 * @param args
	 * @throws InterruptedException
	 */
	public static void main(String[] args) throws InterruptedException {
		ReentrantLockTryLockDemo rt = new ReentrantLockTryLockDemo();
		Thread t1 = new Thread(rt);
		Thread t2 = new Thread(rt);
		t1.start();
		t2.start();
	}

}

 

1.4 Fair lock settings

Reentrant locks can set the fairness of locks. In the constructor of ReentrantLock, fair locks need to maintain a queue (according to the entry order of threads, regardless of priority).

However, due to the high implementation cost and low performance, it is unfair by default.

public class ReentrantLockFairDemo implements Runnable {
	//set fair lock
	public static ReentrantLock fairLock = new ReentrantLock(true);
	
	@Override
	public void run() {
		while(true){
			try {
				fairLock.lock();
				System.out.println("我是_"+Thread.currentThread().getName());
			} catch (Exception e) {
				e.printStackTrace ();
			}finally{
				fairLock.unlock();
			}
		}
	}

	/**
	 * @param args
	 * @throws InterruptedException
	 */
	public static void main(String[] args) throws InterruptedException {
		ReentrantLockFairDemo rt = new ReentrantLockFairDemo();
		Thread t1 = new Thread(rt,"Thread_t1");
		Thread t2 = new Thread(rt,"Thread_t2");
		t1.start();
		t2.start();
	}

 

 

1.5 A good partner for reentrant locks: Condition object

In synchronized, we can use the wait() and notify() methods provided by the Object object to suspend and wake up the thread (suspend and resume in the thread Thread have been abandoned).

In other words, the wait() and notify() methods in the Object object are used in conjunction with synchronized to suspend and wake up threads.

In the reentrant lock, we use the Condition condition object in conjunction with the reentrant lock to achieve thread suspend (await) and wake up (singal).

When using, we need to use the instance method newCondition() in ReentrantLock to get the Condition object, bind the reentrant lock to the corresponding Condition object, and realize the waiting and wake-up of the thread.

The specific methods are described as follows:

await() method: Similar to the wait() method in the Object class, in the Condition interface, the method await() is provided. After the call, the current thread waits and the current lock is released at the same time. The interrupt can be responded to during the waiting process.

awaitUninterruptibly() method: The function is the same as await(), the difference is that it does not respond to interrupts during the waiting process.

singal() method: used to wake up a thread in the waiting queue.

singalAll() method: used to wake up all threads in the waiting queue.

 

public class ReentrantLockCondition implements Runnable{
	public static ReentrantLock lock = new ReentrantLock();
	public static Condition condition = lock.newCondition();
	
	@Override
	public void run() {
		try {
			// lock
			lock.lock();
			System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"获取锁执行等待....");
			//等待,并释放锁
			condition.await();
			System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"开始执行任务....");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"执行完成....");
			lock.unlock();
			System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"线程释放锁....");
		}
	}
	/**
	 * @param args
	 * @throws InterruptedException 
	 */
	public static void main(String[] args) throws InterruptedException {
		// TODO Auto-generated method stub
		Thread t1 = new Thread(new ReentrantLockCondition());
		Thread t2 = new Thread(new ReentrantLockCondition());
		t1.start();
		t2.start();
		Thread.sleep(2000);
		System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"线程获取锁....");
		//重新获取锁
		lock.lock();
		//唤醒
		System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"线程通知T1....");
		condition.signalAll();
		//释放锁
		lock.unlock();
		System.out.println(System.currentTimeMillis()+"_"+Thread.currentThread().getName()+"释放锁....");
	}
}

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326027308&siteId=291194637