Lock of Java Concurrent Programming

1、 Lock lock

java. util. concurrent. locks. Lock

Why do I need lock when I have synchronized?

1.1 reentrantlock

Simple example:

public class TestLock {

    private Lock lock=new reentrantlock();


    private int value;

    public void add(){
        try {
            lock.lock();
            value++;
        } finally {
            lock.unlock();
        }
    }
}

Reentrantlock: reentrant lock new reentrantlock (true): reentrant lock + fair lock

Reentrant lock: a thread has obtained a lock and can obtain the lock again without deadlock. Reentrantlock and synchronized are both reentrant locks.

Fair lock: those who queue first get the lock first.

Examples of reentrant locks:

public class TestLock {

    private Lock lock=new reentrantlock();

    private int value;

    public  void add(){
        try {
            lock.lock();
            value++;
            //已经获取了锁,再进入也要获取锁的print方法,不会产生死锁
            print();
        } finally {
            lock.unlock();
        }
    }

    public  void print(){
        try {
            lock.lock();
            System.out.println("打印内容");
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        new TestLock().add();
    }
}

1.2 reentrantreadwritelock

Example of read / write lock:

public class TestLock {

    private int sum;

    private ReadWriteLock lock=new reentrantreadwritelock(true);

    public int incrAndGet(){
        try {
            lock.writeLock().lock();
            sum++;
            return sum;
        } finally {
            lock.writeLock().unlock();
        }
    }

    public int getSum(){
        try {
            lock.readLock().lock();
            return sum;
        } finally {
            lock.readLock().unlock();
        }
    }
}

Reading is not mutually exclusive, reading and writing are mutually exclusive, and writing is mutually exclusive

It is suitable for scenarios with more reading and less writing.

Why lock it when reading? A: avoid writing while reading.

1.3 usage of condition

The production consumption case is realized by using condition

public class TestLock {

    private int sum;

    Lock lock = new reentrantlock();

    Condition notFull  = lock.newCondition();

    Condition notEmpty=lock.newCondition();

    public void consumer() throws InterruptedException {
        try {
            lock.lock();
            while (sum<=0){
                notEmpty.await();
            }
            sum--;
            System.out.println("消费者:"+sum);
            notFull.signal();
        } finally {
            lock.unlock();
        }
    }

    public void producer() throws InterruptedException {
        try {
            lock.lock();
            while (sum>=20){
                notFull.await();
            }
            sum++;
            System.out.println("生产者:"+sum);
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }


    public static void main(String[] args) {
        TestLock testLock=new TestLock();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (true){
                        testLock.consumer();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (true){
                        testLock.producer();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

1.4 locksupport lock current thread

Use example:

public class TestThread {

    public static void main(String[] args) throws InterruptedException {
        ChildThread childThread = new ChildThread(Thread.currentThread());
        childThread.start();
        LockSupport.park();
        System.out.println("主线程结束");
    }


    private static class ChildThread  extends Thread{

        private Thread thread;

        public ChildThread(Thread thread) {
            this.thread = thread;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(3000);
                System.out.println("模拟一些初始化操作");
                LockSupport.unpark(thread);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Best practices for using locks

2、 Concurrent atomic class

Package of concurrent atomic class: Java util. concurrent. atomic

Use example:

public class TestLock {

   private AtomicInteger atomicInteger=new AtomicInteger();
   
   public int add(){
       return atomicInteger.incrementAndGet();
   }
   
   public int get(){
       return atomicInteger.get();
   }
   
}

The entire implementation of atomicinteger is lock free.

Implementation principle:

Longadder's improvement on atomiclong: segmentation idea.

3、 Concurrent tool class

We already have locks and concurrent atomic classes. Why do we need concurrent tool classes?

Consider the following scenario: there is a method that uses 10 threads to execute each, but only 4 threads can execute at the same time. It's hard to achieve by locking. Therefore, JDK provides us with the following concurrency tool classes.

3.1 semaphore semaphore

Application scenario: control the number of concurrent threads at the same time.

public class TestLock {
    
    //声明4个permits(许可证)的信号量
    Semaphore semaphore = new Semaphore(4);

    public static void main(String[] args) {
        TestLock testLock = new TestLock();
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        testLock.test();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }

    public void test() throws InterruptedException {
        //拿到一个permits(许可证),也可以带参,一个线程拿两个,如:semaphore.acquire(2);
        semaphore.acquire();
        System.out.println(Thread.currentThread().getName() + "在工作");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //释放一个permits
            semaphore.release();
        }
    }

}

3.2 countdownlatch lockout

Application scenario: the master thread waits for all worker threads to finish executing the task.

Example: there are five people in the company. Everyone has finished the work at hand before the boss leaves work.

public class TestLock2 {

    CountDownLatch countDownLatch=new CountDownLatch(5);

    public static void main(String[] args) throws InterruptedException {
        TestLock2 testLock = new TestLock2();
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    testLock.test();
                }
            }).start();
        }
        testLock.countDownLatch.await();
        System.out.println("大家都工作完了,老板(监工)可以下班了");
    }

    public void test() {
        System.out.println(Thread.currentThread().getName() + "在工作");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            countDownLatch.countDown();
            System.out.println(Thread.currentThread().getName() + "工作完了");
        }
    }

}

It is equivalent to countdownlatch has a counter. After calling the await method, it waits there. Each time the countdown method is called, it will be reduced by one. Await will wake up only when the counter is reduced to 0.

3.3 cyclicbarrier fence

Scenario: the task is executed to a certain stage, and other tasks are aligned

It is very similar to countdownlatch in function, but the methods used are different.

Example:

public class TestLock2 {

    CyclicBarrier cyclicBarrier=new CyclicBarrier(5);

    public static void main(String[] args) throws InterruptedException {
        TestLock2 testLock = new TestLock2();
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    testLock.test();
                }
            }).start();
        }

    }

    public void test() {
        System.out.println(Thread.currentThread().getName() + "在工作");
        try {
            int i = new Random().nextInt(10);
            TimeUnit.SECONDS.sleep(i);
            System.out.println(Thread.currentThread().getName() + "工作完了");
           cyclicBarrier.await();
            System.out.println("大家都工作完了,老板(监工)可以下班了");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }

}

The cyclicbarrier does not have a countdown method. Instead, it is blocked to await. When the number of blocks reaches, it can be released.

3.4 AQS synchronization queue

AQS is the abbreviation of abstractqueuedsynchronizer, which is the basis for building locks or other components. Such as countdownlatch, semaphore and reentrantlock.

There are two ways to share resources: exclusive and shared. Exclusive implementations such as reentrantlock and shared implementations such as semaphore. Subclasses are responsible for implementing fair locks or unfair locks.

Take reentrantlock as an example. There is a state variable. If state is 0, it means that it is not locked. Call the tryacquire method to exclusive lock and set state + 1. After that, other threads cannot occupy it and put it in the queue. If it is still called by the current thread, it can obtain the lock again, but the state needs to be accumulated. (reentrant concept) but note that you have to release as many times as you get.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>