多线程---JUC

这篇具有很好参考价值的文章主要介绍了多线程---JUC。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

什么是JUC?

JUC是:java.util.concurrent这个包名的缩写。它里面包含了与并发相关,即与多线程相关的很多东西。我们下面就来介绍这些东西。

Callable接口

Callable接口类似与Runnable接口:
Runnable接口:描述的任务是不带返回值的。
callable接口:描述的任务是带返回值的,存在的意义就是让我们获取到结果
让我们通过下面的代码来仔细体会一下不同

    // 使用Runnable来计算 1+2+.....+1000

    static class Result{
        public int sum;
        public Object locker = new Object();
    }

    public static void main(String[] args) {
        Result result = new Result();
        //创建一个专门的线程来求和
        Thread thread = new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++){
                    result.sum ++;

                }
                synchronized (result.locker){
                    result.locker.notify();
                }
            }
        };
        thread.start();

        // 必须得等thread线程执行完了再打印
        synchronized (result.locker) {

            if (result.sum == 0){
                try {
                    result.locker.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            System.out.println(result.sum);
        }
    }
    // 使用callable来计算1+2+....+1000
    public static void main(String[] args) {
        //使用callable来定义一个任务
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 0; i < 1000; i++){
                    sum++;
                }
                return sum;
            }
        };

        // 用来接受callable任务作为参数
        FutureTask<Integer> futureTask = new FutureTask<>(callable);

        //Thread 里的参数没有callable类型  只有futuretask类型  所以需要创建一个futuretask类型来过渡
        Thread thread = new Thread(futureTask);
        thread.start();

        try {
            System.out.println(futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

ReentrantLock

ReentrantLock,也是可重入锁。它的出现是为了补充synchronized(可重入锁)无法实现的一些操作。

它一共有三个核心的方法:

  • tryLock:试试能不能加上锁,试成功了就加上锁;试失败了就放弃。还可以指定加锁的等待超时时间,超过时间则放弃加锁。
  • lock:加锁
  • unlock:解锁

ReentrantLock VS synchronized

  1. ReentrantLock必须手动调用lock()和unlock()方法,这样如果它们之间出现异常,unlock()方法就有可能调用不到,造成资源浪费。而synchronized则没有这个问题。
       public static void main(String[] args) {
        // 和synchronized相比有三个优势 两个不同
        ReentrantLock reentrantLock = new ReentrantLock();
        try {
            reentrantLock.lock();
        }finally {
            //当在 lock和unlock 之间出现异常时  unlock就无法执行到  需要用到finally来必须执行
            //synchronized不存在这个问题  因为它只要出了代码块就一定会解锁
            reentrantLock.unlock();
        }
    }
  1. ReentrantLock是标准库的一个类,底层是基于Java实现的;synchronized是Java关键字,底层是通过JVM实现的(C++实现的)
  2. tryLock可以尝试加锁并且指定加锁的等待超时时间;synchronized会一直死等。在实际开发中,往往不使用死等。
  3. ReentrantLock可以实现公平锁,通过指定构造方法里的一个参数;synchronized是非公平锁。
        ReentrantLock reentrantLock = new ReentrantLock(true);
  1. ReentrantLock是搭配Condition类实现通知唤醒操作的,唤醒操作可以指定唤醒哪一个线程;synchronized是搭配wait-notify实现通知唤醒操作的,唤醒操作是随机唤醒一个线程。

原子类

原子类的底层是基于CAS实现的,使用原子类最常见的场景就是多线程计数。
CAS操作前面已经非常详细的介绍过,点击此处可以查看浏览

     //原子类  多用于计数
    //count.getAndIncrement   =   count++
    //count.incrementAndGer   =   ++count
    //count.getAndDecrement   =   count--
    //count.decrementAndGer   =   --count
    public static void main(String[] args) {
        AtomicInteger count = new AtomicInteger();

        Thread thread = new Thread(() -> {
            for (int i = 0; i < 50000; i++){
                //相当与count++;
                count.getAndIncrement();
            }
        });

        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 50000; i++){
                //相当于count++;
                count.getAndIncrement();
            }
        });

        thread.start();
        thread1.start();

        try {
            thread.join();
            thread1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(count.get());
    }

线程池

前面已经非常详细的介绍过,点击此处可以查看浏览

信号量Semaphore

信号量的基本操作有两个:
P操作:申请一个资源
V操作:释放一个资源

信号量本身是一个计数器,表示可用资源的个数:
P操作申请一个资源,可用资源的个数就-1
V操作释放一个资源,可用资源的个数就+1
当计数为0时,继续进行P操作就会阻塞,直到其他线程执行V操作释放资源

        // 信号量可以看成更广义的锁   锁就是一个信号量  可用资源数只有1
    public static void main(String[] args) throws InterruptedException {

        // 需要指定初始值 表示可用资源的个数
        Semaphore semaphore = new Semaphore(4);

        semaphore.acquire();
        System.out.println("申请资源");
        semaphore.acquire();
        System.out.println("申请资源");
        semaphore.acquire();
        System.out.println("申请资源");


        semaphore.release();
        System.out.println("释放资源");
        semaphore.release();
        System.out.println("释放资源");

    }

CountDownLatch

CountDownLatch使用的效果:类似于一个跑步比赛,当最后一个选手到达终点就结束。
使用CountDownLatch的时候,首先要设置一下有几个选手参赛,每个选手撞线了就调用一下countDown方法,当撞线次数达到选手的个数时,比赛就结束。

放到程序中理解:
比如:要下载一个很大的文件,把文件分成多部分分别下载。使用多线程执行下载任务,每个线程下载一部分,当所有的线程都下载完毕,整个线程就下载完毕了。文章来源地址https://www.toymoban.com/news/detail-728970.html

	//CountDownLatch
    public static void main(String[] args) {
        // 设置任务的个数
        CountDownLatch downLatch = new CountDownLatch(10);

        for (int i = 0; i < 10; i++){
            Thread thread = new Thread(() -> {
                System.out.println("开始任务" + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("任务结束" + Thread.currentThread().getName());
                downLatch.countDown();

            });
            thread.start();
        }

        try {
            downLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("全部任务都结束");

    }

到了这里,关于多线程---JUC的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【JavaEE初阶】 线程安全

    线程安全是多线程编程是的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且准确的执行,不会出现数据污染等意外情况。上述是百度百科给出的一个概念解释。换言之,线程安全就是某

    2024年02月08日
    浏览(46)
  • 【JavaEE初阶】 线程池详解与实现

    线程池,是一种线程的使用模式,它为了降低线程使用中频繁的创建和销毁所带来的资源消耗与代价。 通过创建一定数量的线程,让他们时刻准备就绪等待新任务的到达,而任务执行结束之后再重新回来继续待命。 想象这么一个场景: 在学校附近新开了一家快递店,老板很

    2024年02月06日
    浏览(29)
  • 多线程(JavaEE初阶系列2)

    目录 前言: 1.什么是线程 2.为什么要有线程 3.进程与线程的区别与联系 4.Java的线程和操作系统线程的关系 5.多线程编程示例 6.创建线程 6.1继承Thread类  6.2实现Runnable接口 6.3继承Thread,使用匿名内部类 6.4实现Runnable接口,使用匿名内部类 6.5lambda表达式创建Runnable子类对象 7.

    2024年02月15日
    浏览(29)
  • 多线程(JavaEE初阶系列4)

    目录 前言: 1.单例模式 1.1饿汉模式 1.2懒汉模式 1.3结合线程安全下的单例模式 1.4单例模式总结 2.阻塞式队列 2.1什么是阻塞队列 2.2生产者消费者模型 2.2.1 上下游模块之间进行“解耦合” 2.2.2削峰填谷 2.3阻塞队列的实现 结束语: 在上节中小编主要与大家分享了多线程中遇到

    2024年02月15日
    浏览(41)
  • 【JavaEE初阶】 线程安全的集合类

    原来的集合类, 大部分都不是线程安全的. Vector, Stack, HashTable, 是线程安全的(不建议用), 其他的集合类不是线程安全的. 为什么不建议使用呢? 因为我们在使用的时候,这些类就会自动的加锁,虽然编译器会自动优化为没有锁竞争的线程进行锁消除的优化,但是呢万一编译器没

    2024年02月08日
    浏览(29)
  • 多线程(JavaEE初阶系列7)

    目录 前言: 1.常见的锁策略 1.1乐观锁和悲观锁 1.2轻量级锁和重量级锁 1.3自旋锁和挂起等待锁 1.4互斥锁与读写锁 1.5可重入锁与不可重入锁 1.6公平锁与非公平锁 2.CAS 2.1什么是CAS 2.2自旋锁的实现 2.3原子类 3.synchronized 3.1synchronized的原理以及基本特点 3.2偏向锁 3.3轻量级锁 3.4重

    2024年02月14日
    浏览(26)
  • 【JavaEE初阶】线程的概念与创建

    本节目标 认识多线程 创建多线程 Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。 一个线程就是一个 “执行流” . 每个线程之间都可以按照顺讯执行自己的代码. 多个线程之

    2024年02月07日
    浏览(30)
  • JavaEE初阶Day 6:多线程(4)

    前序 :针对Day 5结尾的count++ 多线程的执行,是 随机调度抢占式 的执行模式,某个线程执行指令过程中,当它执行到任何一个指令的时候,都有可能被其他线程把它的CPU抢占走 实际并发执行,由于 上述原因 以及 count++本质是CPU的三个指令 ,两个线程执行指令的相对顺序就可

    2024年04月14日
    浏览(21)
  • 【JavaEE初阶】多线程(四)阻塞队列 定时器 线程池

    概念 阻塞队列是一种特殊的队列. 也遵守 “ 先进先出 ” 的原则. 阻塞队列能是一种线程安全的数据结构, 并且具有以下特性: 当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素. 当队列空的时候, 继续出队列也会阻塞,直到有其他线程往队列中插入元素

    2023年04月26日
    浏览(41)
  • JavaEE 初阶篇-深入了解多线程等待与多线程状态

    🔥博客主页: 【 小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录         1.0 线程等待         1.1 线程等待 - join() 方法         1.1.1 main 线程中等待多个线程         1.1.2 main 线程等待 t2 线程且t2 线程等待 t1 线程         1.1.3 其他线程阻塞等待 main 线程

    2024年04月17日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包