JUC介绍 以及JUC中的锁框架

Java JUC 简介
在Java 5.0 提供了java.util.concurrent(简称JUC )包,在此包中增加了在并发编程中很常用的实用工具类。
用于定义类似于线程的自定义子系统,包括线程池、异步IO 和轻量级任务框架。提供可调的、灵活的线程池。还提供了设计用于多线程上下文中的Collection 实现(JUC集合)

锁结构:

在这里插入图片描述
下面这个图更方便理解:
在这里插入图片描述

在本篇文章之前,我们已经对并发机制中出现的很多的常见知识点进行了总结,今天我们来回顾一下有哪些是JUC包中的。

1.volatile关键字:
当多个线程共享某一个变量的时候,可以实现内存可见性(内存中的数据可见),相较于synchronized是一个轻量级的同步机制。但是volatile不保证原子性和有序性还有一个互斥性。
2.JUC中提供的原子变量类:
包括AtomicInteger等Atomic家族类。查看源码即可知道,其中的变量都是用volatile修饰保证内存可见性,通过CAS算法保证数据的原子性。
CAS:三个参数:V( 内存中的值) A 预估值 B更新值 当且仅当V==A时,将B更新值赋给V,否则不做任何操作。
3.1ConcurrentHashMap锁分段机制
a. java5.0在JUC包中提供了多种并发容器来改进同步容器的性能;、
b. concurrentHashMap同步容器是java5增加的一个线程安全的哈希表,对多线程的操作介于HashMap和HashTable之间,内部采用了“锁分段”机制代替了HashTable的独占锁,进而提高性能。
c. 此包还提供了设计用于多线程上下文中的Collection实现:ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList和CopyOnWriteArraySet。当期望许多线程访问一个给定collection时, ConcurrentHashMap通常优于同步的HashMap,ConcurrentSkipListMap通常优于同步的TreeMap.当期望的读数和遍历远远大于列表的更新数时,CopyOnWriteArrList优于同步的ArrayList。
3.2CountDownLatch闭锁操作
 CountDownLatch:闭锁,在完成某些运算时,只有其他所有的线程的运算全部完成,当前运算才算执行。
 CountDownLatch 一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
闭锁可以延迟线程的进度直到其达到终止状态,闭锁可以用来确保某些活动直到其他活动都完成才继续执行:
     确保某个计算在其需要的所有资源都被初始化之后才继续执行
    确保某个服务在其依赖的所有其他服务都已经启动之后才启动
    等待直到某个操作所有参与者都准备就绪在继续执行

 以下代码是用通过闭锁计算10线程执行的时间
4.线程池
线程池:提供了一个线程队列,队列中保存着所有等待状态的线程,避免了创建与销毁额外开销,提高了响应的速度。
Java.util.concurrent.Executor: 负责线程的使用与调度的根接口;
线程池的体系结构:

  • java.util.concurrent.Executor : 负责线程的使用与调度的根接口
  •  |--**ExecutorService 子接口: 线程池的主要接口
    
  •      |--ThreadPoolExecutor 线程池的实现类
    
  •      |--ScheduledExecutorService 子接口:负责线程的调度
    
  •          |--ScheduledThreadPoolExecutor :继承 ThreadPoolExecutor, 实现 ScheduledExecutorService
    

工具类 : Executors

  • ExecutorService newFixedThreadPool() : 创建固定大小的线程池
  • ExecutorService newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。
  • ExecutorService newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程
  • ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务。
    */
    5.Lock:Lock同步锁
      用于解决多线程安全问题的方式。
      synchronized:隐式锁,同步代码块、同步方法。
      Jdk1.5后:同步锁Lock,是一种显式锁 ,需要通过lock()方式上锁,必须通过unlock方法进行释放锁;
    Lock实现线程等待唤醒机制
    6.实现Callable接口:
    创建执行线程的方式三:实现Callble接口。相较于实现Runnable接口的方式,方法可以有返回值,并且可以抛出异常
public class TestCallable {

    public static void main(String[] args) {
        ThreadDemo td = new ThreadDemo();
        // 1.执行Callable方式,需要FutureTask实现类的支持,用于接收运算结果。
        FutureTask<Integer> result = new FutureTask<Integer>(td);
        new Thread(result).start();

        // 2.接收线程运算后的结果
        try {
           Integer sum =  result.get();
           System.out.println(sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

class ThreadDemo implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for(int i = 0; i<=100;i++){
            System.out.println(i);
            sum+=i;
        }
        return sum;
    }
}

7.Condition 控制线程通信
Condition 接口描述了可能会与锁有关联的条件变量
这些变量在用法上与使用Object.wait 访问的隐式监视器类似,但提供了更强大的功能。
需要特别指出的是,单个Lock 可能与多个Condition 对象关联。
为了避免兼容性问题,Condition 方法的名称与对应的Object 版本中的不同。
在Condition 对象中,与wait、notify 和notifyAll 方法对应的分别是await、signal 和signalAll。
Condition 实例实质上被绑定到一个锁上。要为特定Lock 实例获得Condition 实例,请使用其newCondition() 方法。

/*
 * 生产者消费者案例:
 */
public class TestProductorAndConsumerForLock {

    public static void main(String[] args) {
        Clerk clerk = new Clerk();

        Productor pro = new Productor(clerk);
        Consumer con = new Consumer(clerk);

        new Thread(pro, "生产者 A").start();
        new Thread(con, "消费者 B").start();

//       new Thread(pro, "生产者 C").start();
//       new Thread(con, "消费者 D").start();
    }

}

class Clerk {
    private int product = 0;

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

    // 进货
    public void get() {
        lock.lock();

        try {
            if (product >= 1) { // 为了避免虚假唤醒,应该总是使用在循环中。
                System.out.println("产品已满!");

                try {
                    condition.await();
                } catch (InterruptedException e) {
                }

            }
            System.out.println(Thread.currentThread().getName() + " : "
                    + ++product);

            condition.signalAll();
        } finally {
            lock.unlock();
        }

    }

    // 卖货
    public void sale() {
        lock.lock();

        try {
            if (product <= 0) {
                System.out.println("缺货!");

                try {
                    condition.await();
                } catch (InterruptedException e) {
                }
            }

            System.out.println(Thread.currentThread().getName() + " : "
                    + --product);

            condition.signalAll();

        } finally {
            lock.unlock();
        }
    }
}

// 生产者
class Productor implements Runnable {

    private Clerk clerk;

    public Productor(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            clerk.get();
        }
    }
}

// 消费者
class Consumer implements Runnable {

    private Clerk clerk;

    public Consumer(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            clerk.sale();
        }
    }

}

读写锁
线程按序交替
ForkJoinPool分支/合并框架工作窃取

?
Fork Join与线程池的区别
在这里插入图片描述

JUC篇具体介绍:https://blog.csdn.net/cx8122389/article/details/70049425

java多线程各个点的详细介绍 有43篇呢
http://www.cnblogs.com/skywang12345/p/java_threads_category.html

猜你喜欢

转载自blog.csdn.net/mulinsen77/article/details/84586859
JUC
今日推荐