Multithreading learning -ReentrantLock

In front of an implicit learning under synchronized lock, characteristic is to say, bad places also hope the exhibitions

Use ReentrantLock under the following summary of the experience, there are many online about ReentrantLock which is better synchronized and discussions with, we are interested can search about, but also according to their actual situation zone selection

Official API Java 

https://docs.oracle.com/javase/8/docs/api/

ReentrantLock Features

      1. reentrant mutex 

      2. Easy to use, provide fair and unfair competition mode other kinds of locks (synchroinzed a non-level playing field mode)

Official Recommended use

It is recommended practice to always immediately follow a call to lock with a try block, most typically in a before/after construction such as:

 
 class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...
    
   public void m() {
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }

Look at a simple example to understand is functioning under ReentrantLock

public class ReentrantLockDemo {
    
    protected class MyReentrantLockRunnable implements Runnable{
        final ReentrantLock reentrantLock = new ReentrantLock(true); //采用公平竞争模式
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "就绪");
            reentrantLock.lock();//上锁
            try {
                for(int i=0;i<2;i++){
                    System.out.println(Thread.currentThread().getName() + "执行:"+i);
                }
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock(); //无论本次执行是否正常都要释放锁,以免造成死锁
            }
            System.out.println(Thread.currentThread().getName() + "完毕");
        }
    }
    
    public static void main(String[] args){
        ReentrantLockDemo reentrantLockDemo = new ReentrantLockDemo();
        MyReentrantLockRunnable runnable = reentrantLockDemo.new MyReentrantLockRunnable();
        Thread t1 = new Thread(runnable,"t1");
        Thread t2 = new Thread(runnable,"t2");
        t1.start();
        t2.start();
    }
}

运行结果: 

t2就绪

t1就绪

t2执行:0

t2执行:1

t2完毕

t1执行:0

t1执行:1

t1完毕  

从运行结果可以看出t2线程首先获得锁,t1进来后在门外面等t2执行完毕释放锁, 方可获得锁继续执行

ReentrantLock锁的等待和唤醒Condition 

看一个典型的生产者和消费者的例子

车间类定义

/**
 * 描述:〈食品工厂〉
 *
 * @author lyh
 * create on 2018/3/7
 * @version 1.0
 */
public class MakeFoodFactory {

    private ReentrantLock lock = new ReentrantLock(true);
    //生产者状态监听
    Condition customerCondition = lock.newCondition();
    //消费者状态监听
    Condition produceCondition = lock.newCondition();
    //工厂的最大容量 如果使用非阻塞队列效率更高
    BlockingQueue<String> blockingQueue = new LinkedBlockingDeque<>(10);

    /**
     * 消费者行为控制
     * @author lyh
     * Created On 2018/3/7 下午5:14
     */
    public void produce(){
        lock.lock();
        try {
            while (blockingQueue.size()>=3) {//当前队列中的面包数大于3的时候,暂停生产面包
                produceCondition.await();
            }
            blockingQueue.put("添加一个面包");
            System.out.println(Thread.currentThread().getName()+"生产一个面包,当前面包数"+blockingQueue.size());
            Thread.sleep(1000);
            customerCondition.signalAll(); //一旦有面包就喊一下消费者区消费   这可以优化
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 消费者行为控制
     * @author lyh
     * Created On 2018/3/7 下午5:14
     */
    public void customer(){
        try{
            lock.lock();
            while(blockingQueue.isEmpty()){  //当队列中没有面包的时候,等待
                customerCondition.await();
            }
            blockingQueue.take();
            System.out.println(Thread.currentThread().getName()+"消费一个面包,当前面包数" +blockingQueue.size());
            Thread.sleep(1000);
            produceCondition.signalAll();  //这同样也可以优化
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

Production control worker class

/**
 * 工人生产控制
 * @author lyh
 * create on 2018/3/7
 * @version 1.0
 */
public class MakeFoodRunDemo {

    /**
     *  生产面包
     * Created On 2018/3/7 下午4:04
     */
    protected class FoodCustomer implements Runnable{
        private MakeFoodFactory makeFoodFactory;

        FoodCustomer(MakeFoodFactory makeFoodFactory){
            this.makeFoodFactory = makeFoodFactory;
        }

        @Override
        public void run() {
            for(;;){
                makeFoodFactory.customer();
            }
        }
    }
    /**
     *  消费面包
     * Created On 2018/3/7 下午4:05
     */
    protected class FoodProducer implements Runnable{
        private MakeFoodFactory makeFoodFactory;

        FoodProducer(MakeFoodFactory makeFoodFactory){
            this.makeFoodFactory = makeFoodFactory;
        }

        @Override
        public void run() {
            for(;;){
                makeFoodFactory.produce();
            }
        }
    }

    public static void main(String[] args){
        MakeFoodFactory makeFoodFactory = new MakeFoodFactory();
        MakeFoodRunDemo makeFoodRunDemo = new MakeFoodRunDemo();
        FoodProducer producer = makeFoodRunDemo.new FoodProducer(makeFoodFactory);
        FoodCustomer foodCustomer = makeFoodRunDemo.new FoodCustomer(makeFoodFactory);
        Thread t1 = new Thread(producer,"p1");
        Thread t2 = new Thread(producer,"p2");
        Thread t3 = new Thread(foodCustomer,"c1");
        t1.start();
        t2.start();
        t3.start();
    }

}

operation result

p2 produce a loaf of bread, the current number of bread 1
p1 produce a loaf of bread, the current number of bread 2
c1 consumption of bread, the current number of bread 1
p2 produce a loaf of bread, the current number of bread 2
p1 produce a loaf of bread, the current number of bread 3
c1 consumption of bread, The current number of bread 2
p2 produce a loaf of bread, the current number of bread 3
c1 consumption of bread, the current number of bread 2
p2 produce a loaf of bread, the current number of bread 3
c1 consumption of bread, the current number of bread 2
current number of bread p2 produce a loaf of bread, 3
c1 a bread consumption, the current number of bread 2
P2 produce a loaf of bread, bread is currently number 3
c1 a bread consumption, the current number of bread 2
P2 produce a loaf of bread, bread is currently number 3

As can be seen every time the bread queue number greater than or equal to three, began to shut down, waiting for consumers to spend, spend and then went over production. Which control production or consumption is the identity Condition producer and consumer ReentantLock state of this state, to achieve the condition into a wait state. It wakes up every consumer after the consumer complete a producer, if the producer wakes up production to meet the conditions of production, or continue to wait.

Thinking:

   1. Every time a consumer have to wake producer is not necessary?

   2. Every time a production went to wake up a consumer it is not necessary

   3.Condition time thread await () has not released the lock?

For questions 1 and 2, in fact, I think programming like life here is like two workers collaborate together, A1, A2 responsible for making bread, B is responsible for packing bread. Apparently the two production speeds greater than the speed of a person package (assuming a consistent production and packaging used for a time), so the middle there will be a lot of unnecessary notifications, such as B are busy packing when there is no need to shout at Similarly consumers there is no need to shout producers are working. This is the middle there is a need to communicate, if B is not in the package when we Qu Han him, also need to A1, A2 production when we Qu Han people, so that efficiency is the highest.

Third hair problem

Causes the current thread to wait until it is signalled or interrupted.

The lock associated with this Condition is atomically released and the current thread becomes disabled for thread scheduling purposes and lies dormant until one of four things happens:

  • Some other thread invokes the signal() method for this Condition and the current thread happens to be chosen as the thread to be awakened; or
  • Some other thread invokes the signalAll() method for this Condition; or
  • Some other thread interrupts the current thread, and interruption of thread suspension is supported; or
  • A "spurious wakeup" occurs.

In all cases, before this method can return the current thread must re-acquire the lock associated with this condition. When the thread returns it is guaranteed to hold this lock.

When this method is called automatically release the resource lock associated with the lock, and the current thread becomes disabled state,

We add two print statements

 /**
     * 生产行为控制
     * @author lyh
     * Created On 2018/3/7 下午5:14
     */
    public void produce(){
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName()+"获得锁"+blockingQueue.size());//添加打印
            while (blockingQueue.size()>=3) {//当前队列中的面包数大于3的时候,暂停生产面包
                produceCondition.await();
                System.out.println(Thread.currentThread().getName()+"await"+blockingQueue.size());//添加打印
            }
            blockingQueue.put("添加一个面包");
            System.out.println(Thread.currentThread().getName()+"生产一个面包,当前面包数"+blockingQueue.size());
            Thread.sleep(1000);
            //if(blockingQueue.size()>=3) {
            customerCondition.signalAll(); //一旦有面包就喊一下消费者区消费
            //}
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println(Thread.currentThread().getName()+"释放锁");
            lock.unlock();

        }
    }

Results of the
p1 get lock 0
p1 produce a loaf of bread, the current number of bread 1
p1 release the lock
p2 acquire the lock 1
p2 produce a loaf of bread, the current number of bread 2
p2 release lock
c1 consumption of bread, the current number of bread 1
p1 get the lock 1
p1 produce a bread, The current number of bread 2
p1 release the lock
p2 obtain lock 2
p2 produce a loaf of bread, the current number of bread 3
p2 release lock
c1 consumption of bread, the current number of bread 2
p1 get lock 2
p1 produce a loaf of bread, the current number of bread 3
p1 release the lock
p2 obtained lock 3
c1 consumption of bread, the current number of bread 2
p1 get lock 2
p1 produce a loaf of bread, the current number of bread 3
p1 release the lock
p2await3
c1 consumption of bread, the current number of bread 2
p1 get lock 2
p1 produce a loaf of bread, the current bread number 3
p1 release the lock
p2await3
c1 consumption of bread, bread is currently number 2
p1 get lock 2
p1 produce a loaf of bread, bread is currently number 3
p1 release the lock
p2await3
c1 consumption of bread, the current number of bread 2
p1 get lock 2
p1 produce a loaf of bread, the current bread number 3
p1 release the lock
p2await3
c1 consumption of bread, the current number of bread 2
p1 get lock 2
p1 produce a loaf of bread, the current bread number 3
p1 release lock
p2await3

It can be seen in this little fair competition, p2 this state will always be disabled and then wake up in the wake was disable, because the queue to enter p1 p2 in the process is awakened in, so always first execution p1, the size of the queue after executing the p1 becomes 3, p2 will have to wait. await after the current thread is disable, if non-equity policy, the two threads p1 and p2 will wait for the emergence of the situation

reference:

http://www.cnblogs.com/superfj/p/7543927.html 

JAVA Concurrent Programming

JAVA API



Guess you like

Origin blog.csdn.net/leeahuamsg/article/details/79473095