Lock CountDownLatch CyclicBarrier Exchanger Semaphore 原子型操作

一、概述

1.Lock是JDK1.5提供的一个接口;有效的降低死锁的几率,Lock相对于synchronize而言更加灵活

synchronized 问题:容易产生死锁;锁对象不容易找寻确定;不能在方法A中加锁,方法B中解锁

同步代码块问题:容易产生死锁
synchronized(){

}

同步方法问题:锁对象不容易找寻确定
class A {
  // m1方法 的锁对象是 this
  public synchronized void m1(){}
  // m2方法 的锁对象是 A.class
  pubilc synchronized void m2(){}
}

A a1 = new A();
a1.m1(); //m1方法的锁对象是 a1
A a2 = new A();
a2.m1(); //m2方法的锁对象是 a2

2.用的更多的是Lock的实现类:ReentrantLock

3.公平和非公平策略:锁如果不指定,默认是非公平策略

//给上参数true,是公平策略,不给是非公平的,公平策略:多个线程操作同一个资源的时候会去排队,执行完的线程会去排在队伍的最后面
//默认为false,是因为非公平策略下更快,synchronize默认是非公平的
Lock l = new ReentrantLock(true);

4.读写锁:

  a.读锁:允许多个线程读,但不允许写

  b.写锁:允许一个线程写,但不允许线程读

   ReadWriteLock rw1 = new ReentrantReadWriteLock();
   //加读锁
   rw1.readLock().lock();
   //解读锁
   rw1.readLock().unlock();
   //加写锁
   rw1.writeLock().lock();
   //解写锁
   rw1.writeLock().unlock();

代码:

package com.apple.lock;

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

/**
 * This is Description
 *
 * @author apple
 * @date 2020/06/08
 */
public class LockDemo {

    public static void main(String[] args) throws InterruptedException {
        Count c = new Count();

        //给上参数true,是公平策略,不给是非公平的,公平策略:多个线程操作同一个资源的时候会去排队,执行完的线程会去排在队伍的最后面
        //默认为false,是因为非公平策略下更快,synchronize默认是非公平的
        Lock l = new ReentrantLock(true);

        new Thread(new AddRunnable(c, l)).start();
        new Thread(new AddRunnable(c, l)).start();
        new Thread(new AddRunnable(c, l)).start();
        new Thread(new AddRunnable(c, l)).start();

        Thread.sleep(5000);
        System.out.println(c.getCount());

    }
}

class AddRunnable implements Runnable {

    private Count c;
    private Lock l;

    public AddRunnable(Count c, Lock l) {
        this.c = c;
        this.l = l;
    }

    @Override
    public void run() {
        //加锁
        l.lock();
        for (int i = 0; i < 100; i++) {
            c.setCount(c.getCount() + 1);
        }
        //解锁
        l.unlock();
    }
}

class Count {
    private int count;

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}

二、其他

1.CountDownLatch - 闭锁/线程递减锁,用于进行线程计数,当达到指定的计数的时候,会放开阻塞允许后续线程执行

package com.apple.lock;

import java.util.concurrent.CountDownLatch;

/**
 * This is Description
 *
 * @author apple
 * @date 2020/06/09
 */
public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {

        /**
         * 场景:老师和4个考生进行考试,在老师和4个学生进入考场后才能开始考试
         */
        CountDownLatch cdl = new CountDownLatch(5);
        new Thread(new Teacher(cdl)).start();
        new Thread(new Student(cdl)).start();
        new Thread(new Student(cdl)).start();
        new Thread(new Student(cdl)).start();
        new Thread(new Student(cdl)).start();

        //在计数归零之前,就需要陷入阻塞
        cdl.await();
        System.out.println("开始考试");
    }
}

class Teacher implements Runnable {

    private CountDownLatch cdl;

    public Teacher(CountDownLatch cdl) {
        this.cdl = cdl;
    }

    @Override
    public void run() {
        System.out.println("监考老师到达考场~~~");
        //减少1个
        cdl.countDown();
    }
}

class Student implements Runnable {

    private CountDownLatch cdl;

    public Student(CountDownLatch cdl) {
        this.cdl = cdl;
    }

    @Override
    public void run() {
        System.out.println("学生到达考场~~~");
        //减少1个
        cdl.countDown();
    }
}

2.CyclicBarrier:栅栏,用于进行线程的计数

场景:跑步比赛中,所有运动员都先到达起跑线(栅栏),然后再一起跑出去

package com.apple.lock;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * This is Description
 *
 * @author apple
 * @date 2020/06/09
 */
public class CyclicBarrierDemo {
    public static void main(String[] args) {

        //参数:表示对多少线程计数
        CyclicBarrier cb = new CyclicBarrier(4);

        new Thread(new Runner(cb), "1号").start();
        new Thread(new Runner(cb), "2号").start();
        new Thread(new Runner(cb), "3号").start();
        new Thread(new Runner(cb), "4号").start();
    }
}

/**
 * 运动员
 */
class Runner implements Runnable {

    private CyclicBarrier cb;
    
    public Runner(CyclicBarrier cb) {
        this.cb = cb;
    }

    @Override
    public void run() {
        try {
            String name = Thread.currentThread().getName();
            //每个线程准备的时间
            Thread.sleep((long) (Math.random() * 1000));
            System.out.println("运动员-" + name + "-到了起跑线");
            //每个运动员到了起跑线后,需要等待
            //每await一次,就会减少一个计数
            cb.await();
            //当计数为0,意味着可以放开阻塞,即 cb.await() 到 0
            System.out.println("运动员-" + name + "-跑了出去");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}

注意:CountDownLatch 和 CyclicBarrier 的区别

  例如:周末,有6个人去吃饭,其中5个人到了,还有一个人没有到,这时对服务员说,晚点上菜。这种场景下,对于服务员来说就是 CountDownLatch

     而对6个人来说是 CyclicBarrier 。为什么对于服务员是CountDownLatch,因为等第6个人到齐后,开始上菜是一个新的线程事件

3.Exchanger:交换机,用于交换两个线程之间的信息,只能交换2个

package com.apple.lock;

import java.util.concurrent.Exchanger;

/**
 * This is Description
 * 生产者和消费者之间进行商品与钱的交换
 * 生产者给商品货物
 * 消费者给金钱
 *
 * @author apple
 * @date 2020/06/09
 */
public class ExchangerDemo {
    public static void main(String[] args) {
        Exchanger<String> ex = new Exchanger<>();

        new Thread(new Producer(ex)).start();
        new Thread(new Consumer(ex)).start();
    }
}

class Producer implements Runnable {

    private Exchanger<String> ex;

    public Producer(Exchanger<String> ex) {
        this.ex = ex;
    }

    @Override
    public void run() {

        try {
            String info = ex.exchange("货物");
            System.out.println("生产者收到消费者交换的:" + info);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Consumer implements Runnable {

    private Exchanger<String> ex;

    public Consumer(Exchanger<String> ex) {
        this.ex = ex;
    }

    @Override
    public void run() {

        try {
            String info = ex.exchange("钱");
            System.out.println("消费者收到生产者交换的:" + info);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

4.Semaphore:信号量

如果有空余的信号,则来的线程可以取得信号执行,如果没有空余的信号,来的线程就会被阻塞直到有空余信号 - 实际过程中往往用于进行”限流“操作 

如:公交、地铁 - 空座椅个数   餐馆 - 空桌子数,如果有空余的座位,可以去坐,如果没有,则需要等待

package com.apple.lock;

import java.util.concurrent.Semaphore;

/**
 * This is Description
 *
 * @author apple
 * @date 2020/06/09
 */
public class SemaphoreDemo {
    public static void main(String[] args) {

        //参数表示多少信号量
        Semaphore s = new Semaphore(5);
        for (int i = 0; i < 8; i++) {
            new Thread(new Table(s)).start();
        }
    }
}

class Table implements Runnable {

    private Semaphore s;

    public Table(Semaphore s) {
        this.s = s;
    }

    @Override
    public void run() {
        try {
            //信号量需要减少1个,即少一个桌子被占用
            s.acquire();
            System.out.println("过来一个人,一个桌子就被占用");
            Thread.sleep((long) (Math.random() * 10000)); //占用时间//信号增加
            s.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

三、原子型操作

1.可以认为原子性操作是针对属性的锁机制,实际开发中可以用原来习惯的锁来代替

package com.apple.lock;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * This is Description
 *
 * @author apple
 * @date 2020/06/09
 */
public class AtomicDemo {

    //static int i = 0;

    //原子性的属性,底层会自动采用锁机制来保证操作的安全性
    static AtomicInteger ai = new AtomicInteger(0);

    public static void main(String[] args) throws InterruptedException {

        CountDownLatch cdl = new CountDownLatch(2);
        new Thread(new Add(cdl)).start();
        new Thread(new Add(cdl)).start();
      
     //等待上面两个线程执行完成后 cdl.await(); System.out.println(ai); } }
class Add implements Runnable { private CountDownLatch cdl; public Add(CountDownLatch cdl) { this.cdl = cdl; } @Override public void run() { for (int i = 0; i < 10000; i++) { AtomicDemo.ai.incrementAndGet(); } cdl.countDown(); } }

 

posted @ 2020-06-09 15:40  alen-fly  阅读(162)  评论(0编辑  收藏  举报