JUC编程(一)-Lock锁,Condition

一.什么是JUC

JUC是java.util.concurrent的缩写。一共有三个相关的jar包。高并发编程工具包。

JUC编程(一)-Lock锁,Condition

并发编程本质:充分利用CPU资源。

补充:

  • java不能开启线程,start()实际上是调用本地方法start0(),底层的c++方法去开启线程。
  • wait与sleep区别:1.wait属于Object类,sleep属于Thread类。2.sleep不释放锁,wait释放锁。3.wait依赖于synchronized。4.wait需要被唤醒,sleep不需要。

二.Lock锁

  • Lock是一个接口,有三个实现类:
    • ReentrantLock (默认是非公平锁,可以插队;可以手动设置为公平锁)
    • ReentrantReadWriteLock.ReadLock 
    • ReentrantReadWriteLock.WriteLock
  • 对共享资源独占访问:一次只能有一个线程可以获取锁,并且对共享资源的所有访问都要求首先获取锁。
  • 与synchronized区别:
    • lock可以判断锁的状态,synchronized不能
    • lock必须手动释放锁,synchronized自动释放锁
    • synchronized与lock均可重入锁(指某个线程已经获得某个锁,可以再次获取锁而不会出现死锁) ,均为非公平锁。
    • synchronized,一个线程获得锁,另一个线程会一直等待直到其释放锁;lock则不会,可通过lock.tryLock()尝试获取锁。
  • 常用用法:
    Lock lock = new ReentrantLock();
    public void method(){
       lock.lock();
       try {
    	  //同步代码块
       } catch (Exception e) {
    	  e.printStackTrace();
       } finally {
    	  lock.unlock();
       }
    }

三.生产者消费者问题

synchronized实现:

点击查看代码
public class ProCon {
    public static void main(String[] args) {
        Number number = new Number();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    number.add();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"a").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    number.sub();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"b").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    number.add();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"c").start();
        new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    number.sub();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"d").start();
    }
}
/*
    等待,业务处理,通知

 */
class  Number{

    private int num = 0;

    public synchronized void add() throws InterruptedException {
        while (num!=0){
            this.wait();
        }
        num++;
        // num等于0才加1,即num++最大只能为1
        this.notifyAll();
        System.out.println(Thread.currentThread().getName()+"->"+num);
    }

    public synchronized void sub() throws InterruptedException {
        while (num==0){
            this.wait();
        }
        num--;
        this.notifyAll();
        System.out.println(Thread.currentThread().getName()+"->"+num);
    }
}

注:该方法中同步代码块中使用if判断等待存在虚假唤醒的可能性,使用while判断可规避该状况。

Lock锁实现(JUC):

Lock替换synchronized方法和语句的使用,Condition取代了对象监视器Obj。Condition提供与对象监视器类似的方法作用,即await(),signal(),signalAll()对应于wait(),notify(),notifyAll()。 一个Condition实例本质上绑定到一个锁。 要获得特定Condition实例的Condition实例,使用newCondition方法。
点击查看代码
public class ProCon2 {
    public static void main(String[] args) {
        Number2 number2 = new Number2();
        new Thread(()->{ for (int i = 0; i < 5; i++) { number2.add(); } },"a").start();
        new Thread(()->{ for (int i = 0; i < 5; i++) { number2.sub(); } },"b").start();
        new Thread(()->{ for (int i = 0; i < 5; i++) { number2.add(); } },"c").start();
        new Thread(()->{ for (int i = 0; i < 5; i++) { number2.sub(); } },"d").start();
    }
}

class  Number2{

    private int num = 0;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public void add(){
        lock.lock();
        try {
            while (num!=0){
                condition.await();
            }
            num++;
            condition.signalAll();
            System.out.println(Thread.currentThread().getName()+"->"+num);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void sub(){
        lock.lock();
        try {
            while (num==0){
                condition.await();
            }
            num--;
            condition.signalAll();
            System.out.println(Thread.currentThread().getName()+"->"+num);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

Condition的优势:可以精准地唤醒线程

点击查看代码
public class ProCon3 {
    public static void main(String[] args) {
        ThreadTest test = new ThreadTest();
        new Thread(()->{ for (int i = 0; i < 5; i++) { test.A(); } },"a").start();
        new Thread(()->{ for (int i = 0; i < 5; i++) { test.B(); } },"b").start();
        new Thread(()->{ for (int i = 0; i < 5; i++) { test.C(); } },"c").start();
    }
}

class  ThreadTest{

    private int n = 1;
    Lock lock = new ReentrantLock();
    Condition conditionA = lock.newCondition();
    Condition conditionB = lock.newCondition();
    Condition conditionC = lock.newCondition();

    public void A(){
        lock.lock();
        try {
            while (n!=1){
                conditionA.await();
            }
            n = 2;
            // n为1执行业务,唤醒B
            conditionB.signal();
            System.out.println(Thread.currentThread().getName()+"->"+"is A");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void B(){
        lock.lock();
        try {
            while (n!=2){
                conditionB.await();
            }
            n = 3;
            // n为2执行业务,唤醒C
            conditionC.signal();
            System.out.println(Thread.currentThread().getName()+"->"+"is B");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void C(){
        lock.lock();
        try {
            while (n!=3){
                conditionC.await();
            }
            n = 1;
            // n为3执行业务,唤醒A
            conditionA.signal();
            System.out.println(Thread.currentThread().getName()+"->"+"is C");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
上一篇:Java并发之Condition接口


下一篇:Condition实现原理