sychronized可重入、不可中断、非公平;Lock可重入、可中断、非公平和公平;
- Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现,没有区分读写锁
- synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象
发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁(所以建议使用的
try/finally结构),则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁
- Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断
- 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到
Thread类中提供了一个静态方法,可以判断boolean holdsLock(Object obj)
- Lock可以提高多个线程进行读操作的效率。在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。
条件变量就是表示条件的一种变量。但是必须说明,这里的条件是没有实际含义的,仅仅是个标记而已,并且条件的含义往往通过代码来赋予其含义。条件变量都实现了java.util.concurrent.locks.Condition接口,条件变量的实例化是通过一个Lock对象上调用newCondition()方法来获取的,这样,条件就和一个锁对象绑定起来了。因此,Java中的条件变量只能和锁配合使用,来控制并发程序访问竞争资源的安全。
条件变量Condition接口定义了等待/通知两种类型的方法,在线程调用这些方法时,需要提前获取Condition对象关联的锁(在基于wait/notify方法实现的方案中需要获取的是对象锁)。
Condition对象是需要关联Lock对象的,经调用Lock对象的newCondition()对象创建而来,也就是说Condition的使用是需要依赖Lock对象的。
- await()导致当前线程等待,直到其它线程调用该Condition的signal()方法或者signalAll()方法来唤醒该线程
- signal()唤醒在Lock对象上等待的单个线程。如果所有线程都在该Lock对象上等待,则会选择唤醒其中一个线程。选择是任意的
- signalAll()唤醒在此Lock对象上等待的所有线程。只有当前线程放弃对该Lock对象的锁定后,才可以执行被唤醒的线程
存取款轮流操作,各自5个线程,测试结果是否正确
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- public class Test2 {
- public static void main(String[] args) {
- Account a=new Account();
- for(int i=0;i<5;i++) {
- int k=i;
- new Thread(()->{
- a.cunKuan(k);
- }).start();
- new Thread(()->{
- a.quKuan(k);
- }).start();
- }
- }
- }
-
- class Account{
- private long id;
- private double balance;
-
- private Lock lock=new ReentrantLock();//账户锁
-
- private Condition _save=lock.newCondition();//存款条件,一个锁上可以定义无数个条件变量
- private Condition _draw=lock.newCondition();//取款条件
-
- /*
- * 存款
- * >lock.lock(); 获取锁
- * >_save.await(); // 阻塞存款操作, await后就隐示自动释放lock直到被唤醒自动获取
- * >_draw.signalAll();// 唤醒所有等待取款线程
- * lock.unlock(); // 释放锁
- *
- * 取款
- * > lock.lock(); // 获取锁
- * > _draw.await(); // 阻塞取款操作, await后就隐示自动释放lock直到被唤醒自动获取
- * > _save.signalAll(); // 唤醒所有存款操作
- * > lock.unlock(); // 释放锁
- */
-
- public void cunKuan(double num) {
- lock.lock();
- try {
- System.out.println(Thread.currentThread()+"开始存款");
- balance+=num;
- System.out.println(Thread.currentThread()+"存款结束");
- _save.await();
- _draw.signal();
- }catch(Exception e) {
- e.printStackTrace();
- }finally {
- lock.unlock();
- }
- }
- public void quKuan(double num) {
- lock.lock();
- try {
- System.out.println(Thread.currentThread()+"开始存款");
- balance+=num;
- System.out.println(Thread.currentThread()+"存款结束");
- _draw.await();
- _save.signal();
- }catch(Exception e) {
- e.printStackTrace();
- }finally {
- lock.unlock();
- }
- }
- }
用sychronized和Lock接口分别实现生产者和消费者模式
sychronized
- public class Basket {
- private volatile Object obj=null;
-
- public synchronized void produce(Object obj) {
- while(this.obj!=null) {
- try {
- this.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- this.obj=obj;
- this.notifyAll();
- System.out.println("生产了一个对象:"+obj);
- }
-
- public synchronized void consume() {
- while(this.obj==null) {
- try {
- this.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- System.out.println("消费了一个对象:"+obj);
- this.obj=null;
- this.notifyAll();
- }
- }
- import java.util.Date;
-
- public class Test1 {
- public static void main(String[] args) {
- Basket basket=new Basket();
- Thread t1=new Producer(basket);
- Thread t2=new Consumer(basket);
- t1.start();
- t2.start();
- }
- }
-
- class Producer extends Thread{
- private Basket basket;
-
- public Producer(Basket basket) {
- this.basket=basket;
- }
- @Override
- public void run() {
- for(int i=0;i<20;i++) {
- basket.produce(new Date());
- }
- }
- }
-
- class Consumer extends Thread{
- private Basket basket;
-
- public Consumer(Basket basket) {
- this.basket=basket;
- }
- @Override
- public void run() {
- for(int i=0;i<20;i++) {
- basket.consume();
- }
- }
- }
Lock
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
-
- public class Basket2 {
- private volatile Object data=null;
-
- private final Lock lock=new ReentrantLock();
- private final Condition condition=lock.newCondition();
-
- public void produce(Object data) {
- lock.lock();
- try {
- while(this.data!=null) {
- try {
- condition.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- this.data=data;
- condition.signalAll();
- System.out.println("生产了一个对象:"+data);
- }finally {
- lock.unlock();
- }
- }
-
- public void consume() {
- lock.lock();
- try {
- while(data==null) {
- try {
- condition.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- System.out.println("消费了一个对象:"+data);
- this.data=null;
- condition.signalAll();
- }finally {
- lock.unlock();
- }
- }
- }
- import java.util.Date;
-
- public class Test2 {
- public static void main(String[] args) {
- Basket2 basket=new Basket2();
- Thread t1=new Producer2(basket);
- Thread t2=new Consumer2(basket);
- t1.start();
- t2.start();
- }
- }
-
- class Producer2 extends Thread{
- private Basket2 basket;
-
- public Producer2(Basket2 basket) {
- this.basket=basket;
- }
- @Override
- public void run() {
- for(int i=0;i<20;i++) {
- basket.produce(new Date());
- }
- }
- }
-
- class Consumer2 extends Thread{
- private Basket2 basket;
-
- public Consumer2(Basket2 basket) {
- this.basket=basket;
- }
- @Override
- public void run() {
- for(int i=0;i<20;i++) {
- basket.consume();
- }
- }
- }
Lock接口
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
-
- public class Operat {
- private volatile boolean left=true;
-
- private final Lock lock=new ReentrantLock();
- private final Condition ac=lock.newCondition();
- private final Condition bc=lock.newCondition();
-
- public void printA() {
- lock.lock();
- try {
- while(!left)
- try {
- ac.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- left=false;
- System.out.println("A::"+Thread.currentThread());
- bc.signal();
- }finally {
- lock.unlock();
- }
- }
-
- public void printB() {
- lock.lock();
- try {
- while(left) {
- try {
- bc.await();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- left=true;
- System.out.println("B::"+Thread.currentThread());
- ac.signal();
- }finally {
- lock.unlock();
- }
- }
- }
- public class Test2 {
- public static void main(String[] args) {
- Operat op = new Operat();
- for (int k = 0; k < 5; k++) {
- Thread leftHandle = new Thread(() -> {
- for (int i = 0; i < 10; i++) {
- op.printA();
- }
- });
- Thread rightHandle = new Thread(() -> {
- for (int i = 0; i < 10; i++) {
- op.printB();
- }
- });
-
- leftHandle.start();
- rightHandle.start();
- }
- }
- }
Synchronized
- public class Operation {
- private volatile boolean left=true;
-
- public synchronized void printA() {
- while(!left) {
- // System.out.println("A:"+Thread.currentThread()+"begin...");
- try {
- this.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- left=false;
- System.out.println("A::"+Thread.currentThread());
- this.notifyAll();
- }
- public synchronized void printB() {
- while(left) {
- // System.out.println("B:"+Thread.currentThread()+"begin...");
- try {
- this.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- left=true;
- System.out.println("B::"+Thread.currentThread());
- this.notifyAll();
- }
- }
- public class Test1 {
- public static void main(String[] args) {
- Operation op = new Operation();
- for (int k = 0; k < 5; k++) {
- Thread leftHandle = new Thread(() -> {
- for (int i = 0; i < 10; i++) {
- op.printA();
- }
- });
- Thread rightHandle = new Thread(() -> {
- for (int i = 0; i < 10; i++) {
- op.printB();
- }
- });
-
- leftHandle.start();
- rightHandle.start();
- }
- }
- }