您的位置:首页 > 编程语言 > Java开发

Java高并发程序-Chapter3 JDK并发包(第九讲)同步控制之 ReentrantLock 重用锁

2018-03-27 13:23 567 查看


ReentrantLock 重用锁
1. 可重用
import java.util.concurrent.locks.ReentrantLock;

public class ReenterLock implements Runnable {

  public static ReentrantLock reentrantLock = new ReentrantLock();

  public static int i = 0;

  public void run() {

    for (int j = 0; j < 1000000; j++) {

     try {
       reentrantLock.lock();
       reentrantLock.lock(); //可重用
       i++;
     } finally {
       
       reentrantLock.unlock();
       reentrantLock.unlock();
     }
    }

  }
  
  public static void main(String[] args) throws InterruptedException {
    
    ReenterLock reenterLock = new ReenterLock();
    
    Thread t1 = new Thread(reenterLock);
    Thread t2 = new Thread(reenterLock);
    
    t1.start();
    t2.start();
    
    t1.join();
    t2.join();
    
    System.out.println(i);
  }

}在这种情况下,一个线程连续两次获得同一把锁。这是允许的!
如果不允许这么操作,那么同一个线程在第2次获得锁时,将会和自己产生死锁。
程序就会“卡死”在第2次申请锁的过程中。
但需要注意的是,如果同一个线程多次获得锁,那么在释放锁的时候,也必须释放相同次数
如果释放锁的次数多,那么会得到一个 java. lang. legalmonitorstateexception异常,反之,如果释放锁的次数少了,那么相当于线程还持有这个锁。
2. 可中断package com.john.learn.high.concurent.ch03;
import java.util.concurrent.locks.ReentrantLock;
public class InterruptLock implements Runnable {
  public static ReentrantLock lock1 = new ReentrantLock();
  public static ReentrantLock lock2 = new ReentrantLock();
  private int lock;
  public InterruptLock(int lock) {
    this.lock = lock;
  }
  public void run() {
    try {
     if (lock == 1) {
       try {
         lock1.lockInterruptibly();
       } catch (InterruptedException e) {
         e.printStackTrace();
       }
       try {
         lock2.lockInterruptibly();
       } catch (InterruptedException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
       }
       return;
     }
     try {
       lock2.lockInterruptibly();
     } catch (InterruptedException e) {
       e.printStackTrace();
     }
     try {
       lock1.lockInterruptibly();
     } catch (InterruptedException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
     }
     return;
    } finally {
     if (lock1.isHeldByCurrentThread()) {
       lock1.unlock();
     }
     if (lock2.isHeldByCurrentThread()) {
       lock2.unlock();
     }
     System.out.println(Thread.currentThread().getName() + ":退出.");
    }
  }
  
  public static void main(String[] args) throws InterruptedException {
    
    InterruptLock lock1 = new InterruptLock(1);
    
    InterruptLock lock2 = new InterruptLock(2);
    
    Thread thread1 = new Thread(lock1);
    Thread thread2 =  new Thread(lock2);
    
    thread1.start();
    thread2.start();
    
    Thread.sleep(5000);
    //中断一个线程
    thread2.interrupt();
     
  }
}
 线程t1和t2启动后,t1先占用lock1,再占用lock2; t2先占用lock2,再请求lock1。
因此很容易形成t1和t2之间的相互等待。
在这里,对锁的请求,统一使用lockInterruptibly()方法
这是一个可以对中断进行响应的锁申请动作,即在等待锁的过程中,可以响应中断在代码第47行,主线程main处于休眠
,此时,这两个线程处于死锁的状态,在代码第49行,由于t2线程被中断,故t2会放弃对locki的申请,同时释放已获得lock2。
这个操作导致t1线程可以顺利得到lock2而继续执行下去。
执行上述代码,将输出:



3.可限时package com.john.learn.high.concurent.ch03;

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

public class TimeLock implements Runnable {

  public ReentrantLock lock = new ReentrantLock();

  public void run() {

    try {

     if (lock.tryLock(5, TimeUnit.SECONDS)) {

       System.out.println("Get lock successful and in processing. "+ Thread.currentThread().getName());
       
       Thread.sleep(6000);

       return;
     }

     System.out.println("Get lock failed. " + Thread.currentThread().getName());

    } catch (InterruptedException e) {

     e.printStackTrace();

    } finally {

     if (lock.isHeldByCurrentThread()) {

       lock.unlock();
     }
    }

  }

  public static void main(String[] args) throws InterruptedException {

    TimeLock timeLock = new TimeLock();

    Thread thread1 = new Thread(timeLock);
    Thread thread2 = new Thread(timeLock);

    thread1.start();
    thread2.start();

    thread1.join();
    thread2.join();

  }

}
在这里, tryLock()方法接收两个参数,一个表示等待时长,另外一个表示计时单位。
这里的单位设置为秒,时长为5,表示线程在这个锁请求中,最多等待5秒。
如果超过5秒还没有得到锁,就会返回 false。
如果成功获得锁,则返回true在本例中,由于占用锁的线程会持有锁长达6秒,故另一个线程无法在5秒的等待时间内获得锁,因此,请求锁会失败。
Reentrantlock.tryLock()方法也可以不带参数直接运行。
在这种情况下,当前线程会尝试获得锁,如果锁并未被其他线程占用,则申请锁会成功,并立即返回true。
如果锁被其他线程占用,则当前线程不会进行等待,而是立即返回 false。
这种模式不会引起线程等待,因此也不会产生死锁。

输出:



4. 公平锁
public ReentrantLock(boolean fair)

public static ReentrantLock fairLock = new ReentrantLock(true);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  并发编程
相关文章推荐