通过Lock对象以及Condition对象实现多线程同步

通过Lock对象以及Condition对象实现多线程同步

在之前的学习中,无论是通过synchronized建立同步代码块,还是通过synchronized建立同步函数,都是把对象看成一把锁来实现同步,这种解释有点牵强,而且在消费者—生产者的那个实例中,其实还有个问题,那就是在避免线程全部冻结时,没必要把相同功能的线程解冻,只要把其他功能的线程解冻即可,也就是说消费者线程只要解冻生产者线程即可,没必要把其他消费者线程也解冻,为了解决这些问题,java1.5版本推出了同步的升级办法,那就是通过Lock对象和Condition对象实现同步。

新的同步办法不再需要synchronized关键字,而引入了更加形象的Lock。

Lock实质上是是一个接口,在创建对象时,使用Lock的子类ReentrantLock来建立对象。

使用方法:建立对象后,在需要同步的代码前一行写    Lock对象.lock();   ,在同步代码后一行写   Lock对象.unlock();

Lock对象用来控制线程的进出,而对线程的操作则由Condition对象来操作;

对应关系:

wait——await(两者均抛出异常)

notify——signal

notifyAll——signalAll

Condition同样是接口,建立方法(比较神奇)       Condition 对象名=Lock对象.newCondition();

例如:1-9 个数,A线程执行123.然后由B线程接着执行456.最后在由A线程执行789

代码:

package com.huojg.test;

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

/*
 * 
 * 1-9 个数,A线程执行123.然后由B线程接着执行456.最后在由A线程执行789
 * 
 * 
 * **/
public class lock {
    static class NumberWrapper {
        public int value = 1;
    }
    
public static void main(String[] args) {
    
    //初始化可重入锁
    final Lock lock=new ReentrantLock();
    //第一个条件当屏幕上输出到3
    final Condition reachThreeCondition=lock.newCondition();
    //第一个条件当屏幕上输出到6
    final Condition reachSixCondition=lock.newCondition();     
    //NumberWrapper只是为了封装一个数字,一边可以将数字对象共享,并可以设置为final
            //注意这里不要用Integer, Integer 是不可变对象
            final NumberWrapper num = new NumberWrapper();
    //初始化A线程
    Thread threadA=new Thread( new Runnable() {
        public void run() {
            //需要先获得锁
            lock.lock();
            try {
                System.out.println("threadA start write");
                while (num.value<=3) {
                    System.out.println(num.value);
                    num.value++;                    
                }
                //输出到3时要signal,告诉B线程可以开始了
                reachThreeCondition.signal();
            } finally{
                lock.unlock();
            }
            
            lock.lock();
            try {
                //等待输出6的条件
                reachSixCondition.await();
                System.out.println("threadA start write");
                //输出剩余数字
                while (num.value <= 9) {
                    System.out.println(num.value);
                    num.value++;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }                
        }
    });
    
    Thread threadB =new Thread(new  Runnable() {
        public void run() {
        try {
            lock.lock();
            while (num.value<=3) {
                //等待3输出完毕的信号
                reachThreeCondition.await();
            }
            
        }catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
            
            
        try {
            lock.lock();
            //已经收到信号,开始输出4,5,6
            System.out.println("threadB start write");
            while (num.value <= 6) {
                System.out.println(num.value);
                num.value++;
            }
            //4,5,6输出完毕,告诉A线程6输出完了
            reachSixCondition.signal();
            
        } finally{
            lock.unlock();
        }
            
        }
    });

    //启动两个线程
            threadB.start();
            threadA.start();    

}

}

结果:

threadA start write
1
2
3
threadB start write
4
5
6
threadA start write
7
8
9

  

Condition对象的优势在于,signal只能唤醒被相同Condition对象的await方法冻结的线程,因此,可以建立多个Condition对象,分别用来冻结和解冻不同功能的线程

最后要注意的是,Lock接口属于类包Java.util.concurrent.locks

原文地址:https://www.cnblogs.com/huojg-21442/p/7118163.html