Lock的使用

4.1 使用ReentrantLock

在JKD1.5中,新增加了ReentrantLock类也能达到和synchronized关键字同样的效果,并且在扩展功能上更加强大,如嗅探锁定,多路分支通知等功能,在使用上也比synchronized更加灵活。

package ReentrantLock;
/*
 * lock.lock() 代码的线程持有了“对象监视器”,其他线程只有等待锁被释放时再次争抢
 */
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class t1 {
    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        MyThreadA a1 = new MyThreadA(service);
        a1.setName("A");
        a1.start();
        
        MyThreadAA a2 = new MyThreadAA(service);
        a2.setName("AA");
        a2.start();
        
        Thread.sleep(100);
        
        MyThreadB a3 = new MyThreadB(service);
        a3.setName("B");
        a3.start();
        
        MyThreadBB a4 = new MyThreadBB(service);
        a4.setName("BB");
        a4.start();
    }
}

class MyService {
    private Lock lock = new ReentrantLock();
    
    public void MethodA() {
        try {
            lock.lock();
            System.out.println("methodA begin ThreadName=" + Thread.currentThread().getName() + 
                    " time=" + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("methodA end   ThreadName=" + Thread.currentThread().getName() + 
                    " time=" + System.currentTimeMillis());
        }catch (InterruptedException e) {
            // TODO: handle exception
            e.printStackTrace();
        }finally{    //不管是否发生异常,该代码块都执行
            lock.unlock();
        }
    }
    
    public void MethodB() {
        try {
            lock.lock();
            System.out.println("methodB begin ThreadName=" + Thread.currentThread().getName() + 
                    " time=" + System.currentTimeMillis());
            Thread.sleep(5000);
            System.out.println("methodB end   ThreadName=" + Thread.currentThread().getName() + 
                    " time=" + System.currentTimeMillis());
        }catch (InterruptedException e) {
            // TODO: handle exception
            e.printStackTrace();
        }finally{    //不管是否发生异常,该代码块都执行
            lock.unlock();
        }
    }
}

class MyThreadA extends Thread {
    private MyService service;
    
    public MyThreadA(MyService service) {
        this.service = service;
    }
    
    @Override
    public void run() {
        super.run();
        service.MethodA();
    }
}

class MyThreadAA extends Thread {
    private MyService service;
    
    public MyThreadAA(MyService service) {
        this.service = service;
    }
    
    @Override
    public void run() {
        super.run();
        service.MethodA();
    }
}

class MyThreadB extends Thread {
    private MyService service;
    
    public MyThreadB(MyService service) {
        this.service = service;
    }
    
    @Override
    public void run() {
        super.run();
        service.MethodB();
    }
}

class MyThreadBB extends Thread {
    private MyService service;
    
    public MyThreadBB(MyService service) {
        this.service = service;
    }
    
    @Override
    public void run() {
        super.run();
        service.MethodB();
    }
}
methodA begin ThreadName=A time=1603976169500
methodA end   ThreadName=A time=1603976174512
methodA begin ThreadName=AA time=1603976174512
methodA end   ThreadName=AA time=1603976179521
methodB begin ThreadName=B time=1603976179521
methodB end   ThreadName=B time=1603976184522
methodB begin ThreadName=BB time=1603976184522
methodB end   ThreadName=BB time=1603976189534

此实验说明,调用lock.lock()代码的线程就持有了“对象监视器”,其他线程只有等待锁被释放时再次争抢。

 

4.1.3  使用Condition实现等待/通知

类ReentrantLock也可以实现等待/通知模式,需要借助Condition对象。在一个Lock对象里可以创建多个Condition(即对象监视器)实例,线程对象可以注册在指定的Condition中,从而可以有选择地进行线程通知,在调度线程上更加灵活。对比notify/notifyAll方法,被通知的线程却是由JVM随机选择的。

 

/*
 * lock.lock() 代码的线程持有了“对象监视器”,其他线程只有等待锁被释放时再次争抢
 */


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

public class t1 {
    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        MyThread a1 = new MyThread(service);
        a1.start();
        
        Thread.sleep(3000);
        service.signal();
    }
}

class MyService {
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    
    public void await() {
        try {
            lock.lock();
            System.out.println("waitMethod时间为 " + System.currentTimeMillis());
            condition.await();
        }catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
            System.out.println("锁释放了!");
        }
    }
    
    public void signal() {
        try {
            lock.lock();
            System.out.println("signal时间为" + System.currentTimeMillis());
            condition.signal();
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
            System.out.println("我已经唤醒了await()方法,我也该结束了");
        }
    }
}

class MyThread extends Thread {
    private MyService service;
    
    public MyThread(MyService service) {
        this.service = service;
    }
    
    @Override
    public void run() {
        super.run();
        service.await();
    }
}
waitMethod时间为 1603978989457
signal时间为1603978992471
我已经唤醒了await()方法,我也该结束了
锁释放了!

Object类中的wait()相当于Condition类中的await()方法。

Object类中的notify()相当于Condition类中的signal()方法。

/*
 * lock.lock() 代码的线程持有了“对象监视器”,其他线程只有等待锁被释放时再次争抢
 */
package ReentrantLock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class t1 {
    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        MyThreadA a = new MyThreadA(service);
        a.setName("A");
        a.start();
        
        MyThreadB b = new MyThreadB(service);
        b.setName("B");
        b.start();
        

        Thread.sleep(3000);
        //service.signalAll_A();
        service.signalAll_B();
    }
}

class MyService {
    private Lock lock = new ReentrantLock();
    public Condition conditionA = lock.newCondition();
    public Condition conditionB = lock.newCondition();

    
    public void awaitA() {
        try {
            lock.lock();
            System.out.println("begin awaitA时间为  " + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName());
            conditionA.await();
            //Thread.sleep(1000);
            System.out.println("  end awaitA时间为  " + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName());
            
        }catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    
    public void awaitB() {
        try {
            lock.lock();
            System.out.println("begin awaitB时间为  " + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName());
            conditionB.await();
            //Thread.sleep(1000);
            System.out.println("  end awaitB时间为  " + System.currentTimeMillis() + " ThreadName = " + Thread.currentThread().getName());
            
        }catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    
    public void signalAll_A() {
        try {
            lock.lock();
            System.out.println("   signalAll_A时间为 " + System.currentTimeMillis() +" ThreadName=" + Thread.currentThread().getName());
            conditionA.signalAll();
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    
    public void signalAll_B() {
        try {
            lock.lock();
            System.out.println("   signalAll_B时间为 " + System.currentTimeMillis() +" ThreadName=" + Thread.currentThread().getName());
            conditionB.signalAll();
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}

class MyThreadA extends Thread {
    private MyService service;
    
    public MyThreadA(MyService service) {
        this.service = service;
    }
    
    @Override
    public void run() {
        super.run();
        service.awaitA();
    }
}

class MyThreadB extends Thread {
    private MyService service;
    
    public MyThreadB(MyService service) {
        this.service = service;
    }
    
    @Override
    public void run() {
        super.run();
        service.awaitB();
    }
}
begin awaitA时间为  1603982264116 ThreadName = A
begin awaitB时间为  1603982264116 ThreadName = B
   signalAll_B时间为 1603982267131 ThreadName=main
  end awaitB时间为  1603982267131 ThreadName = B

使用ReentrantLock对象可以唤醒指定种类的线程,可以控制部分线程。

 

实现生产者/消费者模式:多对多交替打印

package ReentrantLock;

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

public class t2 {
    public static void main(String[] args) {
        MyService1 myservice = new MyService1();
        
        MyThreadA1[] threada = new MyThreadA1[10];
        MyThreadB1[] threadb = new MyThreadB1[10];
        
        for(int i = 0; i < 10; i++) {
            threada[i] = new MyThreadA1(myservice);
            threadb[i] = new MyThreadB1(myservice);
            
            threada[i].start();
            threadb[i].start();
        }
    }
}

class MyService1 {
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    
    private boolean hasValue = false;
    
    public void set() {
        try {
            lock.lock();
            while(hasValue == true) {
                System.out.println("有可能★★连续");
                condition.await();
            }
            System.out.println("打印★");
            hasValue = true;
            condition.signalAll();
            
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    
    public void get() {
        try {
            lock.lock();
            while(hasValue == false) {
                System.out.println("有可能☆☆连续");
                condition.await();
            }
            
            System.out.println("打印☆");
            hasValue = false;
            condition.signalAll();
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}

class MyThreadA1 extends Thread {
    private MyService1 myservice;
    
    public MyThreadA1(MyService1 myservice) {
        super();
        this.myservice = myservice;
    }
    
    @Override
    public void run() {
        super.run();
        for(int i = 0; i < 10; i++) {
            myservice.set();
        }
    }
}

class MyThreadB1 extends Thread {
    private MyService1 myservice;
    
    public MyThreadB1(MyService1 myservice) {
        super();
        this.myservice = myservice;
    }
    
    @Override
    public void run() {
        super.run();
        for(int i = 0; i < 10; i++) {
            myservice.get();
        }
    }
}
打印★
有可能★★连续
有可能★★连续
打印☆
有可能☆☆连续
打印★
有可能★★连续
打印☆
有可能☆☆连续
有可能☆☆连续
打印★
有可能★★连续
打印☆
有可能☆☆连续
有可能☆☆连续
打印★
有可能★★连续
有可能★★连续
有可能★★连续
有可能★★连续
打印☆
有可能☆☆连续
有可能☆☆连续
...

为了避免死锁,将signal——>signalAll

 

公平锁与非公平锁

公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO的顺序;而非公平锁就是一种获取锁的抢占机制,是随机获得锁的,不一定先到先得,这种方式可能造成某县城一直拿不到锁,结果也就是不公平的。

/*
 * 公平锁
 */
package ReentrantLock;

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

public class t2 {
    public static void main(String[] args) {
        final Service service = new Service(true);    //公平锁
        
        MyThreadA1[] thread = new MyThreadA1[10];
        
        for(int i = 0; i < 10; i++) {
            thread[i] = new MyThreadA1(service);
        }
        
        for(int i = 0; i < 10; i++) {
            thread[i].start();
        }
    }
}

class Service {
    private ReentrantLock lock;
    
    public Service(boolean isFair) {
        super();
        lock = new ReentrantLock(isFair);
    }
    
    public void serviceMethod() {
        try {
            lock.lock();
            System.out.println("ThreadName = " + Thread.currentThread().getName()
                    + "获得锁定");
        }finally {
            lock.unlock();
        }
    }
}


class MyThreadA1 extends Thread {
    private Service myservice ;
    
    public MyThreadA1(Service myservice) {
        this.myservice = myservice;
    }
    
    @Override
    public void run() {
        System.out.println("★线程" + Thread.currentThread().getName() + "运转了");
        myservice.serviceMethod();
    }
}

class MyThreadB1 extends Thread {
    private Service myservice ;
    
    public MyThreadB1(Service myservice) {
        this.myservice = myservice;
    }
    
    @Override
    public void run() {
        System.out.println("☆线程" + Thread.currentThread().getName() + "运转了");
        myservice.serviceMethod();
    }
}
★线程Thread-1运转了
★线程Thread-5运转了
★线程Thread-4运转了
★线程Thread-3运转了
★线程Thread-0运转了
★线程Thread-2运转了
★线程Thread-9运转了
★线程Thread-8运转了
★线程Thread-7运转了
ThreadName = Thread-1获得锁定
★线程Thread-6运转了
ThreadName = Thread-5获得锁定
ThreadName = Thread-4获得锁定
ThreadName = Thread-3获得锁定
ThreadName = Thread-0获得锁定
ThreadName = Thread-2获得锁定
ThreadName = Thread-9获得锁定
ThreadName = Thread-8获得锁定
ThreadName = Thread-7获得锁定
ThreadName = Thread-6获得锁定

打印结果基本是呈有序状态的,这就是公平锁的特点。

 

/*
 * 非公平锁
 */
package ReentrantLock;

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

public class t2 {
    public static void main(String[] args) {
        final Service service = new Service(false);    //非公平锁
        
        MyThreadA1[] thread = new MyThreadA1[10];
        
        for(int i = 0; i < 10; i++) {
            thread[i] = new MyThreadA1(service);
        }
        
        for(int i = 0; i < 10; i++) {
            thread[i].start();
        }
    }
}

class Service {
    private ReentrantLock lock;
    
    public Service(boolean isFair) {
        super();
        lock = new ReentrantLock(isFair);
    }
    
    public void serviceMethod() {
        try {
            lock.lock();
            System.out.println("ThreadName = " + Thread.currentThread().getName()
                    + "获得锁定");
        }finally {
            lock.unlock();
        }
    }
}


class MyThreadA1 extends Thread {
    private Service myservice ;
    
    public MyThreadA1(Service myservice) {
        this.myservice = myservice;
    }
    
    @Override
    public void run() {
        System.out.println("★线程" + Thread.currentThread().getName() + "运转了");
        myservice.serviceMethod();
    }
}

class MyThreadB1 extends Thread {
    private Service myservice ;
    
    public MyThreadB1(Service myservice) {
        this.myservice = myservice;
    }
    
    @Override
    public void run() {
        System.out.println("☆线程" + Thread.currentThread().getName() + "运转了");
        myservice.serviceMethod();
    }
}

 

★线程Thread-0运转了
★线程Thread-4运转了
★线程Thread-3运转了
★线程Thread-2运转了
★线程Thread-7运转了
★线程Thread-1运转了
★线程Thread-9运转了
★线程Thread-8运转了
★线程Thread-6运转了
ThreadName = Thread-0获得锁定
★线程Thread-5运转了
ThreadName = Thread-5获得锁定
ThreadName = Thread-4获得锁定
ThreadName = Thread-3获得锁定
ThreadName = Thread-2获得锁定
ThreadName = Thread-7获得锁定
ThreadName = Thread-1获得锁定
ThreadName = Thread-9获得锁定
ThreadName = Thread-8获得锁定
ThreadName = Thread-6获得锁定

先启动start()的线程不代表先获得锁。

 

1)、方法getHoldCount():其作用是查询当前线程保持此锁定的个数,也就是调用lock()方法的次数。

package ReentrantLock;

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

public class t2 {
    public static void main(String[] args) {
        Service service = new Service();    
        service.serviceMethod();
    }
}

class Service {
    private ReentrantLock lock = new ReentrantLock();
    
    public void serviceMethod() {
        try {
            lock.lock();
            
            System.out.println("serviceMethod getHoldCount = " + lock.getHoldCount());
            
            serviceMethod1();
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        finally {
            lock.unlock();
        }
    }
    
    public void serviceMethod1() {
        try {
            lock.lock();
            
            System.out.println("serviceMethod1 getHoldCount = " + lock.getHoldCount());
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        finally {
            lock.unlock();
        }
    }
    
}
serviceMethod getHoldCount = 1
serviceMethod1 getHoldCount = 2

 

2)、方法int getQueueLength()的作用是返回正等待获取此锁定的线程估计数,比如有5个线程,1个线程首先执行await()方法,那么在调用getQueueLength()方法后返回值是4,说明有4个线程同时在等待lock的释放。

/*
 * 公平锁
 */
package ReentrantLock;

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

public class t2 {
    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();    
        
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.serviceMethod();
            }
        };
        
        Thread[] threadArray = new Thread[10];
        
        System.out.println("一共有10个线程!");
        
        for(int i = 0; i < 10; i++) {
            threadArray[i] = new Thread(runnable);
        }
        
        for(int i = 0; i < 10; i++) {
            threadArray[i].start();
        }
        
        Thread.sleep(2000);
        System.out.println("等待此锁定的线程数有:" + service.lock.getQueueLength());
    }
}

class Service {
    public ReentrantLock lock = new ReentrantLock();
    
    public void serviceMethod() {
        try {
            lock.lock();
            
            System.out.println("ThreadName = " + Thread.currentThread().getName() + "进入方法!");
            
            Thread.sleep(Integer.MAX_VALUE);
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        finally {
            lock.unlock();
        }
    }
}
一共有10个线程!
ThreadName = Thread-0进入方法!
等待此锁定的线程数有:9

 

3)方法int getWaitQueueLength(Condition condition)的作用是返回等待与此锁定相关的给定条件Condition的线程估计数。

package ReentrantLock;

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

public class t2 {
    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();    
        
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };
        
        Thread[] threadArray = new Thread[10];
        
        System.out.println("一共有10个线程!");
        
        for(int i = 0; i < 10; i++) {
            threadArray[i] = new Thread(runnable);
        }
        
        for(int i = 0; i < 10; i++) {
            threadArray[i].start();
        }
        
        Thread.sleep(2000);
        service.notifyMethod();
    }
}

class Service {
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    
    public void waitMethod() {
        try {
            lock.lock();
            condition.await();
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        finally {
            lock.unlock();
        }
    }
    
    public void notifyMethod() {
        try {
            lock.lock();
            System.out.println("有 " + lock.getWaitQueueLength(condition) + "个线程正在等待condition");
            condition.signal();
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}
一共有10个线程!
有 10个线程正在等待condition

  

  • boolean hasQueuedThread(Thread thread):的作用是查询指定的线程是否正在等待获得此锁定
  • boolean hasQueuedThreads():查询是否有线程正在等待获取此锁定
package ReentrantLock;

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

public class t2 {
    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();    
        
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };
        
        Thread threadA = new Thread(runnable);
        threadA.start();
        Thread.sleep(500);
        
        Thread threadB = new Thread(runnable);
        threadB.start();
        Thread.sleep(500);
        
        System.out.println(service.lock.hasQueuedThread(threadA));
        
        //由于threadA发生了睡眠,并且不释放锁;故threadB等待获得此锁定
        System.out.println(service.lock.hasQueuedThread(threadB));
        System.out.println(service.lock.hasQueuedThreads());
    }
}

class Service {
    public ReentrantLock lock = new ReentrantLock();
    public Condition condition = lock.newCondition();
    
    public void waitMethod() {
        try {
            lock.lock();
            Thread.sleep(Integer.MAX_VALUE);
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        finally {
            lock.unlock();
        }
    }
}
false
true
true

 

方法boolean hasWaiters(Condition condition)的作用是查询是否有线程正在等待与此锁定有关的condtion条件。

/*
 * boolean hasWaiters(Condition condition):的作用是否有线程正在等待与此锁定有关的condition条件
 *
 */

package ReentrantLock;

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

public class t2 {
    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();    
        
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };
        
        Thread[] threadArray = new Thread[10];
        
        for(int i=0; i<10; i++) {
            threadArray[i] = new Thread(runnable);
        }
        
        for(int i=0; i<10; i++) {
            threadArray[i].start();
        }
            
        Thread.sleep(2000);
        service.notifyMethod();
    }
}

class Service {
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    
    public void waitMethod() {
        try {
            lock.lock();
            condition.await();
        }catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            lock.unlock();
        }
    }
    
    public void notifyMethod() {
        try {
            lock.lock();
            System.out.println("有没有线程正在等待Condition?" + lock.hasWaiters(condition) + "线程数是多少? " + lock.getWaitQueueLength(condition));
            condition.signal();
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
}
有没有线程正在等待Condition?true线程数是多少? 10

 

4.1.12  方法isFair()、isHeldByCurrentThread()和isLocked()的测试

boolean isFair()的作用是判断是不是公平锁
/*
 * boolean hasWaiters(Condition condition):的作用是否有线程正在等待与此锁定有关的condition条件
 */
package ReentrantLock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class t2 {
    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service(false);    
        
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.serviceMethod();
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
    }

}

class Service {
    private ReentrantLock lock = new ReentrantLock();
    public Service(boolean isFair) {
        super();
        lock = new ReentrantLock(isFair);
    }
    
    public void serviceMethod() {
        try {
            System.out.println("公平锁的情况:" + lock.isFair());
            System.out.println("当前线程是否保持此锁定:" + lock.isHeldByCurrentThread());
            lock.lock();
            System.out.println("当前线程是否保持次锁定:" + lock.isHeldByCurrentThread());
        }catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            lock.unlock();
        }
    }
    
}
公平锁的情况:false
当前线程是否保持此锁定:false
当前线程是否保持次锁定:true

 

方法boolean isLocked()的作用是查询此锁定是否由任意线程保持

package ReentrantLock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class t2 {
    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service(false);    
        
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.serviceMethod();
            }
        };
        Thread thread = new Thread(runnable);
        thread.start();
    }

}

class Service {
    private ReentrantLock lock = new ReentrantLock();
    public Service(boolean isFair) {
        super();
        lock = new ReentrantLock(isFair);
    }
    
    public void serviceMethod() {
        try {
            System.out.println("此锁定是否由任意线程保持:" + lock.isLocked());
            lock.lock();
            System.out.println("此锁定是否由任意线程保持:" + lock.isLocked());
        }catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            lock.unlock();
        }
    }
    
}
此锁定是否由任意线程保持:false
此锁定是否由任意线程保持:true

 

4.1.13  方法lockInterruptibly()、tryLock()和tryLock(long timeout, TimeUnit unit)

/*
 * void lockInterruptibly() 如果当前线程未被中断,则获取锁定,如果已经被中断则出现异常; 相反void lock() 如果当前线程被interrupt中断了,lock()则不出现异常
 */
package ReentrantLock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class t2 {
    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();    
        
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };
        Thread thread = new Thread(runnable);
        thread.setName("A");
        thread.start();
        
        Thread.sleep(5000);
        Thread threadB = new Thread(runnable);
        threadB.setName("B");
        threadB.start();
        threadB.interrupt();
        System.out.println("main end!");
    }

}

class Service {
    public ReentrantLock lock = new ReentrantLock();
    public Condition condition = lock.newCondition();
    
    public void waitMethod() {
        try {
            lock.lockInterruptibly();
            System.out.println("lock begin " + Thread.currentThread().getName());
            
            for(int i=0; i<Integer.MAX_VALUE / 10; i++) {
                String newString = new String();
                Math.random();
            }
            System.out.println("lock end" + Thread.currentThread().getName());
            
        }catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            lock.unlock();
        }
    }
    
}
lock begin A
lock endA
main end!
java.lang.InterruptedException
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(Unknown Source)
	at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(Unknown Source)
	at ReentrantLock.Service.waitMethod(t2.java:38)
	at ReentrantLock.t2$1.run(t2.java:15)
	at java.lang.Thread.run(Unknown Source)
Exception in thread "B" java.lang.IllegalMonitorStateException
	at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(Unknown Source)
	at java.util.concurrent.locks.ReentrantLock.unlock(Unknown Source)
	at ReentrantLock.Service.waitMethod(t2.java:51)
	at ReentrantLock.t2$1.run(t2.java:15)
	at java.lang.Thread.run(Unknown Source)

 

方法 boolean tryLock()的作用是,仅在调用时,锁定未被另一个线程保持的情况下,才获取该锁定。

/*
 * void lockInterruptibly() 如果当前线程未被中断,则获取锁定,如果已经被中断则出现异常; 相反void lock() 如果当前线程被interrupt中断了,lock()则不出现异常
 */
package ReentrantLock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class t2 {
    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();    
        
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                service.waitMethod();
            }
        };
        Thread thread = new Thread(runnable);
        thread.setName("A");
        thread.start();
        Thread.sleep(5000);
        Thread threadB = new Thread(runnable);
        threadB.setName("B");
        threadB.start();
    }

}

class Service {
    public ReentrantLock lock = new ReentrantLock();
    
    public void waitMethod() {
        if(lock.tryLock()) {
            System.out.println("锁定未被保持 " + Thread.currentThread().getName() + "获得锁");
        }else {
            System.out.println("锁定被保持 " + Thread.currentThread().getName() + "没有获得锁");
        }
    }
}
锁定未被保持 A获得锁
锁定被保持 B没有获得锁

  

boolean tryLock(long timeout, TimeUnit unit)的作用是,如果锁定在等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁定,且返回true;

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

public class t2 {
    public static void main(String[] args) throws InterruptedException {
        final Service service = new Service();    
        
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "调用waitMethod时间:" + System.currentTimeMillis());
                service.waitMethod();
            }
        };
        Thread thread = new Thread(runnable);
        thread.setName("A");
        thread.start();

        Thread threadB = new Thread(runnable);
        threadB.setName("B");
        threadB.start();
    }

}

class Service {
    public ReentrantLock lock = new ReentrantLock();
    
    public void waitMethod() {
        try {
            if(lock.tryLock(3, TimeUnit.SECONDS)) {
                System.out.println("       " + Thread.currentThread().getName() + "获得锁的时间: " + System.currentTimeMillis());
                Thread.sleep(10000);
            }else {
                System.out.println("       " + Thread.currentThread().getName() + "没有获得锁");
            }            
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }finally {
            if(lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

    }
}
A调用waitMethod时间:1604308949222
B调用waitMethod时间:1604308949222
       A获得锁的时间: 1604308949223
       B没有获得锁

 

awaitUninterruptibly()方法和await()方法的区别

  1. 线程调用condition.await()方法后,线程处于await状态,此时若在调用thread.interrupt(),会报错!
  2. 而线程调用condition.awaitUninterruptibly()方法后,再调用thread.interrupt()则不会报错!

情况1

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

public class t2 {
    public static void main(String[] args) throws InterruptedException {
        try {
            Service service = new Service();
            
            MyThread thread = new MyThread(service);
            thread.start();
            Thread.sleep(3000);
            thread.interrupt();
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }

}

class Service {
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    
    public void testMethod() {
        try {
            lock.lock();
            System.out.println("wait begin!");
            condition.await();
            System.out.println("wait end!");
        }catch (Exception e) {
            e.printStackTrace();
            System.out.println("catch");
        }finally {
            lock.unlock();
        }

    }
}

class MyThread extends Thread    {
    private Service service;
    public MyThread(Service service) {
        super();
        this.service = service;
    }
    
    @Override
    public void run() {
        // TODO 自动生成的方法存根
        super.run();
        service.testMethod();
    }
}
wait begin!
java.lang.InterruptedException
catch
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.reportInterruptAfterWait(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(Unknown Source)
	at ReentrantLock.Service.testMethod(t2.java:31)
	at ReentrantLock.MyThread.run(t2.java:55)

 

情况2

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

public class t2 {
    public static void main(String[] args) throws InterruptedException {
        try {
            Service service = new Service();
            
            MyThread thread = new MyThread(service);
            thread.start();
            Thread.sleep(3000);
            thread.interrupt();
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }

}

class Service {
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    
    public void testMethod() {
        try {
            lock.lock();
            System.out.println("wait begin!");
            condition.awaitUninterruptibly();
            System.out.println("wait end!");
        }catch (Exception e) {
            e.printStackTrace();
            System.out.println("catch");
        }finally {
            lock.unlock();
        }

    }
}

class MyThread extends Thread    {
    private Service service;
    public MyThread(Service service) {
        super();
        this.service = service;
    }
    
    @Override
    public void run() {
        // TODO 自动生成的方法存根
        super.run();
        service.testMethod();
    }
}
wait begin!

从打印信息看,condition.awaitUninterruptibly() 不会报错

 

4.1.15  方法awaitUntil()的使用

awaitUntil(Date deadline):当前线程进入等待状态直到被通知,中断或者到了某个时间deadline。

package ReentrantLock;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class t2 {
    public static void main(String[] args) throws InterruptedException {
        try {
            Service service = new Service();
            MyThread thread = new MyThread(service);
            thread.start();
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }

}

class Service {
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    
    public void waitMethod() {
        try {
            Calendar calendarRef = Calendar.getInstance();    //获得一个Calendar类型的对象
            calendarRef.add(Calendar.SECOND, 10);
            
            lock.lock();
            System.out.println("wait begin timer = " + System.currentTimeMillis());
            condition.awaitUntil(calendarRef.getTime());
            System.out.println("wait   end timer = " + System.currentTimeMillis());
        
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }
    
    public void notifyMethod() {
        try {
            Calendar calendarRef = Calendar.getInstance();
            calendarRef.add(Calendar.SECOND, 10);
            lock.lock();
            System.out.println("notify begin timer = " + System.currentTimeMillis());
            condition.signalAll();
            System.out.println("notify   end timer = " + System.currentTimeMillis());
        }catch (Exception e) {
            e.printStackTrace();
            System.out.println("catch");
        }finally {
            lock.unlock();
        }

    }
}

class MyThread extends Thread    {
    private Service service;
    public MyThread(Service service) {
        super();
        this.service = service;
    }
    
    @Override
    public void run() {
        // TODO 自动生成的方法存根
        super.run();
        service.waitMethod();
    }
}

class MyThread1 extends Thread    {
    private Service service;
    public MyThread1(Service service) {
        super();
        this.service = service;
    }
    
    @Override
    public void run() {
        // TODO 自动生成的方法存根
        super.run();
        service.notifyMethod();
    }
}
wait begin timer = 1604391980471
wait   end timer = 1604391990461

从打印信息可以看出,线程到了deadline,就自动唤醒,可以没有notify()。

当然线程在等待时间到达前,可以被其他线程提前唤醒。

package ReentrantLock;
import java.util.Calendar;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class t2 {
    public static void main(String[] args) throws InterruptedException {
        try {
            Service service = new Service();
            
            MyThread thread = new MyThread(service);
            thread.start();
            
            Thread.sleep(2000);
            
            MyThread1 thread1 = new MyThread1(service);
            thread1.start();
            
        }catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }

}

class Service {
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    
    public void waitMethod() {
        try {
            Calendar calendarRef = Calendar.getInstance();    //获得一个Calendar类型的对象
            calendarRef.add(Calendar.SECOND, 10);
            
            lock.lock();
            System.out.println("wait begin timer = " + System.currentTimeMillis());
            condition.awaitUntil(calendarRef.getTime());
            System.out.println("wait   end timer = " + System.currentTimeMillis());
        
        }catch (Exception e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }

    }
    
    public void notifyMethod() {
        try {
            Calendar calendarRef = Calendar.getInstance();
            calendarRef.add(Calendar.SECOND, 10);
            lock.lock();
            System.out.println("notify begin timer = " + System.currentTimeMillis());
            condition.signalAll();
            System.out.println("notify   end timer = " + System.currentTimeMillis());
        }catch (Exception e) {
            e.printStackTrace();
            System.out.println("catch");
        }finally {
            lock.unlock();
        }

    }
}

class MyThread extends Thread    {
    private Service service;
    public MyThread(Service service) {
        super();
        this.service = service;
    }
    
    @Override
    public void run() {
        // TODO 自动生成的方法存根
        super.run();
        service.waitMethod();
    }
}

class MyThread1 extends Thread    {
    private Service service;
    public MyThread1(Service service) {
        super();
        this.service = service;
    }
    
    @Override
    public void run() {
        // TODO 自动生成的方法存根
        super.run();
        service.notifyMethod();
    }
}
wait begin timer = 1604392229770
notify begin timer = 1604392231757
notify   end timer = 1604392231757
wait   end timer = 1604392231757

可见线程thread被线程thread1唤醒了,不过要等唤醒线程运行完后,thread才能继续执行 System.out.println("wait end timer = " + System.currentTimeMillis());

如果设置的sleep() 等待时间 超过deadline,那么thread就自动唤醒,打印结果就如下:

wait begin timer = 1604392400427
wait   end timer = 1604392410415
notify begin timer = 1604392420410
notify   end timer = 1604392420410

  

 

posted @ 2020-10-29 22:40  Peterxiazhen  阅读(375)  评论(0编辑  收藏  举报