Lock的使用

Posted xiazhenbin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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对象可以唤醒指定种类的线程,可以控制部分线程。

 

以上是关于Lock的使用的主要内容,如果未能解决你的问题,请参考以下文章

并发包java.util.concurrent.locks.Lock

并发技术12线程锁技术的使用

java并发线程锁技术的使用

Java多线程与并发库高级应用-工具类介绍

ReentrantReadWriteLock场景应用

java中ReentrantReadWriteLock读写锁的使用