java并发编程之Lock

在java5以后引入了另外一种方式实现同步,就是Lock

synchronized锁的缺陷

如果一个代码块被synchronized关键字进行修饰了,当一个线程获取了对应的锁,并且执行该代码块的时候,其他线程只能一直等待,直到获取锁的线程释放掉锁,释放锁有两种情况:

       1:获取锁的线程执行完了该代码块,然后会自动释放锁

       2:执行线程发生了异常,此时JVM会自定释放掉线程的锁

那么如果这个获取锁的线程由于要等待IO或者其他原因(调用了sleep方法),但是又没有释放锁,其他线程只能等待,很影响程序的执行效率

如果利用sysnchronized关键字修饰同步方法,如果一个线程在进行读的操作,那么其他线程即使是读,也都是悲观锁的实现,很影响程序的执行效率,因此就需要一种机制来使得多个线程都只是进行读操作,线性之间不会发生冲突,通过Lock就可以实现,此外通过Lock可以知道有没有获取到锁,这在sysnchronized中是无法办到的

总结:
      1)Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;

  2)Lock和synchronized有一点非常大的不同,采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。

Lock

Lock是一个接口,源码如下:

package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;

/**
 *
 * @see ReentrantLock
 * @see Condition
 * @see ReadWriteLock
 *
 * @since 1.5
 * @author Doug Lea
 */
public interface Lock {

    /**
     * 用来获取锁,如果锁已被其他线程获取,则进行等待。
     * 必须主动去释放锁,并且在发生异常时,不会自动释放锁。
     * 一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,   
     * 以保证锁一定被被释放,防止死锁的发生。
     */
    void lock();

    /**
     * 通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待
     * 状态。也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程
     * A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的
     * 等待过程。
     * 由于lockInterruptibly()的声明中抛出了异常,所以lock.lockInterruptibly()必须放在try
     * 块中或者在调用lockInterruptibly()的方法外声明抛出InterruptedException。
     */
    void lockInterruptibly() throws InterruptedException;

    /**
     * 用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),
     * 则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。
     */
    boolean tryLock();

    /**
     * 该方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。
     * 如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。
     */
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

    /**
     * 释放锁
     */
    void unlock();

    /**
     * 获取Condition类,Condition是Java提供了来实现等待/通知的类,Condition类还提供比
     * wait/notify更丰富的功能,Condition对象是由lock对象所创建的。但是同一个锁可以创建多个
     * Condition的对象,即创建多个对象监视器。这样的好处就是可以指定唤醒线程。notify唤醒的线
     * 程是随机唤醒一个。
     */    
    Condition newCondition();
}

子父类继承/实现关系:

ReentrantLock(可重入锁)

ReentrantLock是一个可重入且独占式的锁,它具有与使用synchronized监视器锁相同的基本行为和语义,但与synchronized关键字相比,它更灵活、更强大,增加了轮询、超时、中断等高级功能。ReentrantLock,顾名思义,它是支持可重入锁的锁,是一种递归无阻塞的同步机制。除此之外,该锁还支持获取锁时的公平和非公平选择。

ReentrantLock内方法及抽象类:

ReentrantLock的类图如下:

ReentrantLock的使用

lock()方法的使用:

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

public class LockExample1 {
	 private Lock lock = new ReentrantLock();
	public static void main(String[] args) {
		final LockExample1 example = new LockExample1();
		new Thread(){
			public void run(){
				example.getLockOrUnLock(Thread.currentThread());
			}
		}.start();
		
		new Thread(){
			public void run(){
				example.getLockOrUnLock(Thread.currentThread());
			}
		}.start();
	}
	public void getLockOrUnLock(Thread currentThread) {
		lock.lock();
		try {
			System.out.println(currentThread.getName()+"获得了锁");
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			System.out.println(currentThread.getName()+"释放了锁");
			lock.unlock();
		}
		
	}
}


运行结果:

Thread-0获得了锁
Thread-0释放了锁
Thread-1获得了锁
Thread-1释放了锁

tryLock()方法的使用:

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

public class LockExample {
	 private Lock lock = new ReentrantLock();
	public static void main(String[] args) {
		final LockExample example = new LockExample();
		new Thread(){
			public void run(){
				example.tryLockOrUnLock(Thread.currentThread());
			}
		}.start();
		
		new Thread(){
			public void run(){
				example.tryLockOrUnLock(Thread.currentThread());
			}
		}.start();
	}
	public void tryLockOrUnLock(Thread currentThread) {
		if(lock.tryLock()){
			try {
				System.out.println(currentThread.getName()+"获得了锁");
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				System.out.println(currentThread.getName()+"释放了锁");
				lock.unlock();
			}
		}else{
			System.out.println("获取锁失败");
		}
		
	}
}

运行结果:

Thread-1获取锁失败
Thread-0获得了锁
Thread-0释放了锁

lockInterruptibly()方法的使用:

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

//测试类
public class LockExample2 {
	private Lock lock = new ReentrantLock();
	public static void main(String[] args) {
		LockExample2 example = new LockExample2();
		MyThread myThread = new MyThread(example);
		MyThread myThread2 = new MyThread(example);
		myThread.start();
		myThread2.start();
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		myThread2.interrupt();
	}
	
	public void getLockOrUnLock(Thread currentThread) throws InterruptedException{
		lock.lockInterruptibly(); //注意,如果需要正确中断等待锁的线程,必须将获取锁放在外面,然后将InterruptedException抛出
		try {
			System.out.println(currentThread.getName()+"获得了锁");
			long startTime = System.currentTimeMillis();
			for(;;){
				if(System.currentTimeMillis() - startTime > Integer.MAX_VALUE){
					break;
					//
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			System.out.println(currentThread.getName()+"执行finally");
			lock.unlock();
			System.out.println(currentThread.getName()+"释放了锁");
		}
		
	}
}



//线程类
public class MyThread extends Thread {
	
	private LockExample2 lockExample2 = null;
	
	public MyThread(LockExample2 lockExample2) {
		this.lockExample2 = lockExample2;
	}

	public void run(){
		try {
			lockExample2.getLockOrUnLock(Thread.currentThread());
		} catch (InterruptedException e) {
			System.out.println(Thread.currentThread().getName() + "被中断");
			e.printStackTrace();
		}
	}
}


运行结果:

Thread-0获得了锁
Thread-1被中断
java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
	at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
	at com.zyf.eflying.lock.LockExample2.getLockOrUnLock(LockExample2.java:23)
	at com.zyf.eflying.lock.MyThread.run(MyThread.java:13)

 

 

ReadWriteLock

是一个接口,源码如下:

package java.util.concurrent.locks;

/**
 * @see ReentrantReadWriteLock
 * @see Lock
 * @see ReentrantLock
 * @desc ReadWriteLock管理一组锁,一个是读锁,一个是写锁
 * @since 1.5
 * @author Doug Lea
 */
public interface ReadWriteLock {
    /**
     * Returns the lock used for reading.
     * 返回一个读锁
     * @return the lock used for reading
     */
    Lock readLock();

    /**
     * Returns the lock used for writing.
     * 返回一个写锁
     * @return the lock used for writing
     */
    Lock writeLock();
}

 

子父类继承关系:

 

补充中...

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值