ReentrantLock的lockInterruptibly和lock响应中断区别以及常见的锁汇总

java.util.concurrent.locks.ReentrantLock

1.lock.lockInterruptibly();立即响应中断:

public class TestLockInterruptibly {
    static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        Thread thread1 = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    doPrint("thread 1 get lock.");
                    do123();
                    doPrint("thread 1 end.");

                } catch (InterruptedException e) {
                    doPrint("thread 1 is interrupted.");
                }
            }
        });

        Thread thread2 = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    doPrint("thread 2 get lock.");
                    do123();
                    doPrint("thread 2 end.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    doPrint("thread 2 is interrupted!!!");
                }
            }
        });

        thread1.setName("thread 1");
        thread2.setName("thread 2");
        thread1.start();
        try {
            Thread.sleep(1000);// 等待一会使得thread1会在thread2前面执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread2.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 1秒后把线程2中断
        thread2.interrupt();
    }

    private static void do123() throws InterruptedException {
        lock.lockInterruptibly();//等待锁的过程中会立即响应中断
        doPrint(Thread.currentThread().getName() + " is locked.");
        try {
            doPrint(Thread.currentThread().getName() + " doSoming1....");
            Thread.sleep(10000);// 等待几秒方便查看线程的先后顺序
            doPrint(Thread.currentThread().getName() + " doSoming2....");

            doPrint(Thread.currentThread().getName() + " is finished.");
        } finally {
            lock.unlock();
        }
    }

    private static void doPrint(String text) {
        System.out.println((new Date()).toLocaleString() + " : " + text);
    }
}

2018-8-7 16:16:21 : thread 1 doSoming1....
2018-8-7 16:16:22 : thread 2 get lock.
java.lang.InterruptedException
2018-8-7 16:16:23 : thread 2 is interrupted!!!
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:896)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1221)
    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:340)
    at com.thinkgem.jeesite.test.TestLockInterruptibly.do123(TestLockInterruptibly.java:60)
    at com.thinkgem.jeesite.test.TestLockInterruptibly.access$1(TestLockInterruptibly.java:59)
    at com.thinkgem.jeesite.test.TestLockInterruptibly$2.run(TestLockInterruptibly.java:31)
    at java.lang.Thread.run(Thread.java:722)
2018-8-7 16:16:31 : thread 1 doSoming2....
2018-8-7 16:16:31 : thread 1 is finished.
2018-8-7 16:16:31 : thread 1 end.

2.lock.lock();

在中断点才会响应中断,比如sleep()

public class TestLockInterruptibly {
	static ReentrantLock lock = new ReentrantLock();

	public static void main(String[] args) {
		Thread thread1 = new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					doPrint("thread 1 get lock.");
					do123();
					doPrint("thread 1 end.");

				} catch (InterruptedException e) {
					doPrint("thread 1 is interrupted.");
				}
			}
		});

		Thread thread2 = new Thread(new Runnable() {

			@Override
			public void run() {
				try {
					doPrint("thread 2 get lock.");
					//do123();
					do321();
					doPrint("thread 2 end.");
				} catch (InterruptedException e) {
					e.printStackTrace();
					doPrint("thread 2 is interrupted!!!");
				}
			}
		});

		thread1.setName("thread 1");
		thread2.setName("thread 2");
		thread1.start();
		try {
			Thread.sleep(1000);// 等待一会使得thread1会在thread2前面执行
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		thread2.start();

		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		// 1秒后把线程2中断
		thread2.interrupt();
	}

	private static void do123() throws InterruptedException {
		lock.lockInterruptibly();
		doPrint(Thread.currentThread().getName() + " is locked.");
		try {
			doPrint(Thread.currentThread().getName() + " doSoming1....");
			Thread.sleep(10000);// 等待几秒方便查看线程的先后顺序
			doPrint(Thread.currentThread().getName() + " doSoming2....");

			doPrint(Thread.currentThread().getName() + " is finished.");
		} finally {
			lock.unlock();
		}
	}
	
	private static void do321() throws InterruptedException {
		lock.lock();
		doPrint(Thread.currentThread().getName() + " is locked.");
		try {
			doPrint(Thread.currentThread().getName() + " doSoming1....");
			Thread.sleep(10000);// 此时才会响应中断
			doPrint(Thread.currentThread().getName() + " doSoming2....");

			doPrint(Thread.currentThread().getName() + " is finished.");
		} finally {
			lock.unlock();
		}
	}

	private static void doPrint(String text) {
		System.out.println((new Date()).toLocaleString() + " : " + text);
	}
}

2018-8-7 16:23:08 : thread 1 get lock.
2018-8-7 16:23:08 : thread 1 is locked.
2018-8-7 16:23:08 : thread 1 doSoming1....
2018-8-7 16:23:09 : thread 2 get lock.
2018-8-7 16:23:18 : thread 1 doSoming2....
2018-8-7 16:23:18 : thread 1 is finished.
2018-8-7 16:23:18 : thread 1 end.
2018-8-7 16:23:18 : thread 2 is locked.
2018-8-7 16:23:18 : thread 2 doSoming1....
java.lang.InterruptedException: sleep interrupted
2018-8-7 16:23:18 : thread 2 is interrupted!!!
    at java.lang.Thread.sleep(Native Method)
    at com.thinkgem.jeesite.test.TestLockInterruptibly.do321(TestLockInterruptibly.java:79)
    at com.thinkgem.jeesite.test.TestLockInterruptibly.access$2(TestLockInterruptibly.java:74)
    at com.thinkgem.jeesite.test.TestLockInterruptibly$2.run(TestLockInterruptibly.java:32)
    at java.lang.Thread.run(Thread.java:722)
已经收到中断请求,但是还是拿到锁,doSoming1...,sleep 才中断

3.常见锁汇总

四种情况:修饰代码块,修饰了方法,修饰了静态方法,修饰BaseClass的class对象。那这几种情况会有什么不同呢?

修饰代码块

这种情况下我们创建了一个对象lock,在代码中使用synchronized(lock)这种形式,它的意思是使用lock这个对象的内置锁。这种情况下就将锁的控制交给了一个对象。当然这种情况还有一种方式:

public void do() {

  synchronized (this) {

    System.out.println("is base");

  }

}

使用this的意思就是当前对象的锁。这里也道出了内置锁的关键,我提供一把锁来保护这块代码,无论哪个线程来都面对同一把锁咯。

修饰方法

synchronized 修饰方法时锁定的是调用该方法的对象,谁调的这个同步方法,我锁定谁

package com.thinkgem.jeesite.test;

public class Test implements Runnable{
	private int b = 100;
	public static void main(String[] args) throws InterruptedException {
		Test task = new Test();
		Thread thread = new Thread(task);
		thread.setName("thread-1");
		thread.start();
		task.m2();
		System.out.println("main thread b="+task.b);
	}
	
	synchronized void m1() throws InterruptedException{
		b=1000;
		Thread.sleep(500);
		System.out.println("b="+b);
	}
	
	synchronized void m2() throws InterruptedException{
		Thread.sleep(250);
		b=2000;
	}

	@Override
	public void run() {
		try {
			m1();
		} catch (Exception e) {
			// TODO: handle exception
		}
		
	}

}

 输出:

main thread b=1000
b=1000

主线程调用thread-1线程,thread-1调用m1()方法,这时thread-1拿到了thread-1的内置锁,锁定了同步代码块m1

task.m2()是当前类调用m2,拿到Test类的内置锁,锁定了同步代码块m2

不是同一个锁,所以不能互斥,各执行各的

修饰静态方法

静态方法难道有啥不一样吗?确实是不一样的,此时获取的锁已经不是this了,而this对象指向的class,也就是类锁。因为Java中的类信息会加载到方法常量区,全局是唯一的。这其实就提供了一种全局的锁。

修饰类的Class对象

这种情况其实和修改静态方法时比较类似,只不过还是一个道理这种方式可以提供更灵活的控制粒度。

java.util.concurrent.locks.Lock

前面看了synchronized,大部分的情况下差不多就够啦,但是现在系统在并发编程中复杂性是越来越高,所以总是有许多场景synchronized处理起来会比较费劲。或者像<java并发编程>中说的那样,concurrent中的lock是对内部锁的一种补充,提供了更多的一些高级特性。

ReentrantLock

ReentrantLock就是可重入锁,连名字都这么显式。ReentrantLock提供了和synchronized类似的语义,但是ReentrantLock必须显式的调用,比如:

public class BaseClass {

  private Lock lock = new ReentrantLock();

  public void do() {

    lock.lock();

    try {

    //....

    } finally {

     lock.unlock();

    }

  }

}

这种方式对于代码阅读来说还是比较清楚的,只不过有个问题,就是如果忘了加try finally或忘 了写lock.unlock()的话导致锁没释放,很有可能导致一些死锁的情况,synchronized就没有这个风险。

猜你喜欢

转载自blog.csdn.net/xuanfuhuo4769/article/details/81483695
今日推荐