1.Synchronized与Lock的区别

2.Condition的根底概念

3.应用Condition循环程序打印ABC

1.Condition的根底概念
咱们可能对于Condition类都比拟生疏,所以咱们从咱们比拟相熟的Synchronized开始比照着学习。
咱们都晓得Synchronized都有下图这三个应用办法:

首先是咱们已知的最纯熟的synchronized关键字,他是保障线程同步用的,而后是Thread.notify()(唤醒所有正在期待中的线程),Thread.wait()(将该线程退出期待队列)。
然而咱们的Lock接口也有相似的三个办法:

其中,lock()办法对应着synchronize的sync,Lock接口下的condition(咱们将在下文进行介绍)中有等同于notify()的signal(),和wait()的await()。

所以总结地说,Synchronized和Lock有以下区别。
1.原始形成:
synchronized是关键字,属于JVM层面
lock是具体类,是api层面

2.应用办法
synchronized不须要用户区手动开释锁,除非运行结束或者抛异样
lock须要用户手动去开释锁,就有可能呈现死锁景象,个别配合try finally来开释锁。

3.加锁是否偏心
synchronized:非偏心
lock:非偏心(构造方法可抉择,默认非偏心)

4.期待是否可中断
synchronized不可中断,除非执行结束或者抛出异样
reentrantlock可中断,可设置超时办法,设置interrupt办法

5,绑定condition
synchronized不能绑定
condition用来实现分组所须要的唤醒的线程们,能够准确唤醒,而不是像synchronized随机唤醒一个,或者唤醒全副的线程。

2.Condition的根底概念
从上文刚刚简略的介绍能够看出,condition是用来准确唤醒某一个线程的,接下来咱们就来系统地介绍一下condition:
Cindition,它是用来代替传统的Object的wait()、notify()实现线程间的合作,相比应用Object的wait()、notify(),应用Condition的await()、signal()这种形式实现线程间合作更加平安和高效。因而通常来说比拟举荐应用Condition,阻塞队列实际上是应用了Condition来模仿线程间合作。

3.应用Condition循环程序打印ABC
既然Condition是用来准确唤醒线程的,那么咱们接下来实现一个小Demo,创立三个线程,让他们按程序循环打印ABC,A打印5次,B打印10次,C打印15次,并且应用Condition准确唤醒:

咱们将要用到一下变量:

    //一个信号量 1代表打印A的线程应该被唤醒,2代表B,3代表C    private int number = 1;    //一把锁    private Lock lock = new ReentrantLock();    //c1,c2,c3用来准确唤醒的线程    private Condition c1 = lock.newCondition();    private Condition c2 = lock.newCondition();    private Condition c3 = lock.newCondition();

接下来咱们定义三个办法:

    public void print5() {    }    public void print10() {    }    public void print15() {    }

咱们将会启动多个线程,别离运行print5(),print10(),print15()办法,
通过condition管制,在print5()完结后,启动print10(),print10()完结后,启动print15()办法,始终循环。

接下别离来看一下三个函数的函数体:

  public void print5() {        //加锁,每次只有一个线程能运行        lock.lock();        try {            //number作为信号量,为1的时候就应该执行print5()办法            while (number != 1) {                //如果不是1,此线程就期待                c1.await();            }            //执行打印办法            for (int i = 1; i <= 5; i++) {                System.out.println(Thread.currentThread().getName() + "\t" + i);            }            //接下来应该轮到print10()办法启动了            number = 2;            //唤醒print10()所领有的的线程            c2.signal();        } catch (InterruptedException e) {            e.printStackTrace();        } finally {            lock.unlock();        }    }    public void print10() {        //加锁,每次只有一个线程能运行        lock.lock();        try {            //number作为信号量,为2的时候就应该执行print10()办法            while (number != 2) {                //如果不是2,此线程就期待                c2.await();            }            for (int i = 1; i <= 10; i++) {                System.out.println(Thread.currentThread().getName() + "\t" + i);            }            //接下来应该轮到print15()办法启动了            number = 3;            //唤醒print15()所领有的的线程            c3.signal();        } catch (InterruptedException e) {            e.printStackTrace();        } finally {            lock.unlock();        }    }    public void print15() {        //加锁,每次只有一个线程能运行        lock.lock();        try {            while (number != 3) {                //如果不是3,此线程就期待                c3.await();            }            for (int i = 1; i <= 15; i++) {                System.out.println(Thread.currentThread().getName() + "\t" + i);            }            //接下来又回到print5()办法启动了            number = 1;            //唤醒print5()所在线程            c1.signal();        } catch (InterruptedException e) {            e.printStackTrace();        } finally {            lock.unlock();        }    }

从正文咱们能够看出,通过Lock加锁,能够每次只让一个办法进行,通过number信号量和三个condition,能够准确地唤醒对应地线程,接下来,咱们别离创立线程,来执行一下这三个办法:

   public static void main(String[] args) {        ShareResources shareResources = new ShareResources();        for (int i = 1; i < 5; i++) {            new Thread(() -> {                shareResources.print5();            }, "A").start();        }        for (int i = 1; i < 5; i++) {            new Thread(() -> {                shareResources.print10();            }, "B").start();        }        for (int i = 1; i < 5; i++) {            new Thread(() -> {                shareResources.print15();            }, "C").start();        }    }

再看一下执行后果:

执行胜利!

总结:
通过这篇博客,咱们总结了Synchronized与Lock的区别,得出synchronized是能够全副换成lock的,而且lock的管制比synchronized更家准确和自在一点,还是用了Lock进行线程的程序循环输入。