20.ReenterLock重入锁

import java.util.concurrent.locks.ReentrantLock;

/**
 * 重入锁 ReenterLock 一个线程允许连续获得同一把锁,注意:必须释放相同次数,释放次数多,会异常,少了相当于线程还持有这个锁,其他线程无法进入临界区
 * 需要手动指定何时加锁何时释放锁
 *
    ReenterLock几个重要方法:
    - lock():获得锁,如果锁已经被占用,则等待
    - lockInterruptibly():获得锁,但优先响应中断
    - tryLock():尝试获得锁,成功返回true,失败返回false,该方法不等待,立即返回
    - tryLock(long time,TimeUnit unit):在给定时间内尝试获得锁
    - unlock():释放锁
 */
public class ReentrantLockDemo implements Runnable{
    public static Integer i = 0;
    public static ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        for (int j = 0; j < 10000000; j++) {
            lock.lock();
            try {
                i++;
            }finally {
                lock.unlock();
            }
        }
    }
    public static void main(String[] args) throws InterruptedException{
        ReentrantLockDemo r = new ReentrantLockDemo();
        Thread thread1 = new Thread(r);
        Thread thread2 = new Thread(r);
        thread1.start();thread2.start();
        thread1.join();thread2.join();
        System.out.println(i);//20000000
    }
}

中断处理

import java.util.concurrent.locks.ReentrantLock;

/**
 * 避免死锁
 * 重入锁的中断处理能力
 */
public class IntLock implements Runnable{
    public static ReentrantLock lock1 = new ReentrantLock();
    public static ReentrantLock lock2 = new ReentrantLock();
    int lock;
    public IntLock(int lock) {
        this.lock = lock;
    }
    @Override
    public void run() {
        try {
            if (lock==1){
                lock1.lockInterruptibly();
                Thread.sleep(500);
                lock2.lockInterruptibly();//可以对中断进行响应的锁
            }else {
                lock2.lockInterruptibly();
                Thread.sleep(500);
                lock1.lockInterruptibly();  //22行
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            //检查当前线程是否拥有该锁
            if (lock1.isHeldByCurrentThread()) lock1.unlock();
            if (lock2.isHeldByCurrentThread()) lock2.unlock();
            System.out.println(Thread.currentThread().getId()+":线程退出");
        }
    }
    public static void main(String[] args) throws InterruptedException{
        IntLock i1 = new IntLock(1);
        IntLock i2 = new IntLock(2);
        Thread t1 = new Thread(i1);
        Thread t2 = new Thread(i2);
        t1.start();
        t2.start();
        Thread.sleep(1000);
        t2.interrupt(); //中断t2 ,t2放弃对lock1的申请,同时释放已获得的lock2
        //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.combat.IntLock.run(IntLock.java:22)
        //	at java.lang.Thread.run(Thread.java:748)
        //10:线程退出
        //9:线程退出
    }
}

限时等待

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

/**
 * 限时等待锁
 */
public class TimeLockDemo implements Runnable{
    public static ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        try {
            if (lock.tryLock(5, TimeUnit.SECONDS)){ //等待时间,计时单位
                Thread.sleep(6000);
            }else {
                System.out.println("get lock failed");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (lock.isHeldByCurrentThread())lock.unlock();
        }
    }
    public static void main(String[] args){
        TimeLockDemo demo = new TimeLockDemo();
        Thread t1 = new Thread(demo);
        Thread t2 = new Thread(demo);
        t1.start();
        t2.start();
    }
    //get lock failed
    //由于占用锁的线程为6秒,另一个线程无法在5秒的等待时间内获得锁,因此请求锁失败
}
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * tryLock
 * 限时等待锁 无参数  如果锁被其他线程占用,则当前线程不会进行等待,而是立即返回false,不会引起线程等待
 */
public class TimeLockDemo2 implements Runnable{
    public static ReentrantLock lock1 = new ReentrantLock();
    public static ReentrantLock lock2 = new ReentrantLock();
    int lock;
    public TimeLockDemo2(int lock) {
        this.lock = lock;
    }
    @Override
    public void run() {
        if (lock == 1){
            while (true){
                if (lock1.tryLock()){
                    try {
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        if (lock2.tryLock()){
                            try {
                                System.out.println(Thread.currentThread().getId()+":my job done");
                                return;
                            } finally {
                                lock2.unlock();
                            }
                        }
                    } finally {
                        lock1.unlock();
                    }
                }
            }
        }else {
            while (true){
                if (lock2.tryLock()){
                    try {
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        if (lock1.tryLock()){
                            try {
                                System.out.println(Thread.currentThread().getId()+":my job done");
                                return;
                            } finally {
                                lock1.unlock();
                            }
                        }
                    } finally {
                        lock2.unlock();
                    }
                }
            }
        }
    }
    public static void main(String[] args){
        TimeLockDemo2 r1 = new TimeLockDemo2(1);
        TimeLockDemo2 r2 = new TimeLockDemo2(1);
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
        t1.start();
        t2.start();
    }
    //9:my job done
    //10:my job done
}

公平锁

import java.util.concurrent.locks.ReentrantLock;

/**
 * 公平锁
 * synchronized产生的锁是非公平锁
 * 重入锁可以设置公平性
 */
public class FairLock implements Runnable{
    public static ReentrantLock lock = new ReentrantLock(true);
    @Override
    public void run() {
        while (true){
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName()+"获得锁");
            } finally {
                lock.unlock();
            }
        }
    }
    public static void main(String[] args) throws InterruptedException{
        FairLock lock = new FairLock();
        Thread t1 = new Thread(lock, "thread_t1");
        Thread t2 = new Thread(lock, "thread_t2");
        t1.start();
        t2.start();
    }
    //...
    //thread_t2获得锁
    //thread_t1获得锁
    //thread_t2获得锁
    //thread_t1获得锁
    //thread_t2获得锁
    //...
    //两个线程基本交替获得锁

    //而非公平锁,一个线程会倾向于再次获得已持有的锁,这种分配方式是高效的,但无公平性可言
}
posted @ 2019-08-21 14:36  fly_bk  阅读(706)  评论(0编辑  收藏  举报