百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

每日一练进击大厂「DAY8」并发编程5

suiw9 2024-11-17 15:50 16 浏览 0 评论

文章目录

  • 一、ReadWriteLock
  • 二、interrupted和isInterrupted方法的区别
  • 三、Semaphore
  • 四、CyclicBarrier
  • 五、happens-before模型
  • 六、fail-safe和fail-fast
  • 七、阻塞队列的有界和无界
  • 八、分布式锁
  • 九、如何实现幂等
  • 十、线程池如何知道一个线程的任务已经执行完成
  • 总结

一、ReadWriteLock

ReadWriteLock是一个读写锁的接口,ReentrantLock是ReadWriteLock接口的一个具体实现,实现了读写的分离,读锁是共享的,写锁是独占的,读和读之间不会互斥,读和写、写和读、写和写之间才会互斥,提高了读写的性能。

二、interrupted和isInterrupted方法的区别

Thread.interrupt()来中断一个线程就会设置中断标记为true,当中断线程调用静态方法Thread.interrupted()来检查中断状态时,中断状态会被标记为false;非静态方法isInterrupted()用来查询其他线程的中断状态且不会改变中断状态标记,任何抛出InterruptedException异常的方法都会将中断状态置为false。
interrupt()通知线程需要结束,如果线程在waiting会抛出InterruptedException,线程自己决定要不要结束,异常会触发复位。
isInsterrupted()获取线程的中断标记,但是不会进行复位操作。
interrupted()获取线程的中断标记,并且主动执行复位操作。

public class InterruptDemo implements Runnable {
    @Override
    public void run() {
        while (!Thread.currentThread().isInterrupted()) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                System.out.println("异常里的isInterrupted:" + Thread.currentThread().isInterrupted());
                Thread.currentThread().interrupt();//再次中断
                System.out.println("再次中断:" + Thread.currentThread().isInterrupted());
            }
        }
        System.out.println("线程结束");
    }
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new InterruptDemo());
        t1.start();
        Thread.sleep(1000);
        t1.interrupt();
    }
}


public class InterruptedDemo {
    public static void main(String[] args) {

        Thread.currentThread().interrupt();
        //查询中断状态,中断标记被标记为true
        System.out.println(Thread.interrupted());
        //获取线程的中断状态,本来应该是true,但是interrupted()触发了复位 所以为false
        System.out.println(Thread.currentThread().isInterrupted());

    }
}

三、Semaphore

public class SemaphoreDemo {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(5);
        for (int i = 0; i < 10; i++) {
            new Car(i, semaphore).start();
        }
    }

    static class Car extends Thread {
        private int num;
        private Semaphore semaphore;

        public Car(int num, Semaphore semaphore) {
            this.num = num;
            this.semaphore = semaphore;
        }

        public void run() {
            try {
                semaphore.acquire();//获取一个许可
                System.out.println("第" + num + "占用 一个停车位");
                TimeUnit.SECONDS.sleep(2);
                System.out.println("第" + num + "俩车走喽");
                semaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

四、CyclicBarrier

public class CyclicBarrierDemo extends Thread {
    @Override
    public void run() {
        System.out.println("开始进行数 据分析");
    }

    public static void main(String[] args) {
        CyclicBarrier cycliBarrier = new CyclicBarrier(3, new CyclicBarrierDemo());
        new Thread(new DataImportThread(cycliBarrier, "file 1")).start();
        new Thread(new DataImportThread(cycliBarrier, "file 2")).start();
        new Thread(new DataImportThread(cycliBarrier, "file 3")).start();
    }
}

public class DataImportThread extends Thread{
    private CyclicBarrier cyclicBarrier;
    private String path;

    public DataImportThread(CyclicBarrier cyclicBarrier, String path) {
        this.cyclicBarrier = cyclicBarrier;
        this.path = path;
    }

    @Override
    public void run() {
        System.out.println("开始导入: "+path+" 位置的数据");
        try {
            cyclicBarrier.await();//阻塞
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}

五、happens-before模型

前者对后者可见

  1. 程序顺序规则:处理器不能对存在依赖关系的操作进行重排序,因为重排序会改变程序的执行结果,对于没有依赖关系的指令,即使重排序,也不会改变在单线程环境下的执行结果。
  2. volatile变量规则:volatile修饰的变量的写操作,一定happens-before后续对于volatile变量的读操作。
  3. 监视器锁:一个线程对于一个锁的释放锁操作,一定happens-before与后续线程对这个锁的加锁操作。
  4. start规则:start()操作之前的操作一定happens-before start()操作。
  5. join规则:join之前的操作的结果,对于join之后的操作可见。
  6. 6)传递性规则(单线程):a happens-before b , b happens-before c , a happens-before c
    a的结果对b可见,b的结果对c可见,那么a的结果对c可见。

六、fail-safe和fail-fast

fail-safe和fail-fast是多线程并发操作集合时的一种失败处理机制。

fail-fast表示快速失败,在集合遍历过程中,一旦发现容器中的数据被修改了,会立刻抛出ConcurrentModificationException异常,从而导致遍历失败。
例如:定义一个Map集合,使用Iterator迭代器进行数据遍历,在遍历过程中对集合数据做变更时,就会发生fail-fast。java.util包下的集合类都是快速失败机制的,常见的使用fail-fast方式遍历的容器有HashMap和ArrayList。

fail-safe表示失败安全,也就是在这种机制下,出现集合元素的修改,不会抛出ConcurrentModificationException,原因是采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历,由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到。

例如:定义一个CopyOnWriteArrayList,在对这个集合遍历过程中,对集合元素做修改后,不会抛出异常,但同时也不会打印出增加的元素。java.util.concurrent包下的容器都是安全失败的,可以在多线程下并发使用,并发修改。常见的使用fail-safe方式遍历的容器有ConcurrentHashMap和CopyOnWriteArrayList。

七、阻塞队列的有界和无界

阻塞队列:当队列为空时,获取队列中元素的消费者线程被阻塞,同时唤醒生产者线程,当队列满了,向队列中添加元素的生产者线程被阻塞,同时唤醒消费者线程。ArrayBlockingQueue是基于数组结构的阻塞队列,也就是队列元素是存储在一个数组结构里面,并且由于数组有长度限制,为了达到循环生产和循环消费的目的,ArrayBlockingQueue用到了循环数组。

有界:阻塞队列中能够容纳的元素个数,通常情况下是有界的,ArrayBlockingList,可以在构造方法中传入一个整形的数字,表示这个基于数组的阻塞队列中能够容纳的元素个数,这种就是有界队列。

无界:就是没有设置固定大小的队列,不过并不是像我们理解的那种元素没有任何限制,而是它的元素存储量很大,像LinkedBlockingQueue,它的默认长度是Integer.Max_Value。

八、分布式锁

分布式锁,是一种跨进程的跨机器节点的互斥锁,它可以用来保证多机器节点对于共享资源的排他性。分布式锁和线程锁本质上是一样的,线程锁的生命周期是单进程多线程,分布式锁的生命周期是多进程多机器节点。
二者都满足以下特性:

  • 排他性,也就是说同一时刻只能有一个节点去访问共享资源;
  • 可重入性,允许一个已经获得锁的进程,在没有释放锁之前再次重新获得锁;
  • 锁的获取、释放的方法;
  • 锁的失效机制,避免死锁的问题。

Redis里面提供了SETNX命令可以实现锁的排他性,当key不存在就返回1,存在就返回0,可以用expire命令设置锁的失效时间,从而避免死锁问题。

Redisson这个开源组件,就提供了分布式锁的封装实现,并且内置了一个Watch Dog机制来对key做续期

九、如何实现幂等

幂等是指一个方法被多次重复执行的时候产生的影响和第一次执行的影响相同。
幂等的核心思想就是保证这个接口的执行结果只影响一次,后续即便再次调用,也不能对数据产生影响。

  1. 使用数据库的唯一约束实现幂等,对于数据插入类的场景,比如创建订单,因为订单号肯定是唯一的,所以如果是多次调用就会触发数据库的唯一约束异常,从而避免一个请求创建多个订单的问题。
  2. 使用redis里面提供的setNX指令,比如对于MQ消费的场景,为了避免MQ重复消费导致数据多次被修改的问题,可以在接受到MQ的消息时,把这个消息通过setNX写入到redis里面,一旦这个消息被消费过,就不会再次消费。
  3. 使用状态机来实现幂等,所谓的状态机是指一条数据的完整运行状态的转换流程,比如订单状态,因为它的状态只会向前变更,所以多次修改同一条数据的时候,一旦状态发生变更,那么对这条数据修改造成的影响只会发生一次。

十、线程池如何知道一个线程的任务已经执行完成

在线程池内部,当我们把一个任务丢给线程池去执行,线程池会调度工作线程来执行这个任务的run方法,run方法正常结束,也就意味着任务完成了,所以线程池中的工作线程是通过同步调用任务的run()方法并且等待run方法返回后,再去统计任务的完成数量。
如果想在线程池外部去获得线程池内部任务的执行状态,有几种方法可以实现:

  1. 线程池提供了一个isTerminated()方法,可以判断线程池的运行状态,我们可以循环判断isTerminated()方法的返回结果来了解线程池的运行状态,一旦线程池的运行状态是Terminated,意味着线程池中的所有任务都执行完了,想要通过这个方法获取状态的前提是,程序中主动调用了线程池的shutdown()方法,在实际业务中,一般不会主动去关闭线程池,因此这个方法在实用性和灵活性方面都不是很好。
  2. 在线程池中,有一个submit()方法,它提供了一个Future的返回值,我们通过Future.get()方法来获得任务的执行结果,当线程池中的任务没执行完之前,future.get()方法会一直阻塞,直到任务执行结束,因此,只要future.get()方法正常返回,也就意味着传入到线程池中的任务已经执行完成了。
  3. 可以引入一个CountDownLatch计数器,它可以通过初始化指定一个计数器进行倒计时,其中有两个方法分别是await()阻塞线程,以及countDown()进行倒计时,一旦倒计时归零,所有被阻塞在await()方法的线程都会被释放,我们可以定义一个CountDownLatch对象并且计数器为1,接着在线程池代码块后面调用await()方法阻塞主线程,然后当传入到线程池中的任务执行完成后,调用countDown()方法表示任务执行结束。最后计数器归零,唤醒阻塞在await()方法的线程。

总结

每天都要有新的希望,如同重获新生一般!

相关推荐

俄罗斯的 HTTPS 也要被废了?(俄罗斯网站关闭)

发布该推文的ScottHelme是一名黑客,SecurityHeaders和ReportUri的创始人、Pluralsight作者、BBC常驻黑客。他表示,CAs现在似乎正在停止为俄罗斯域名颁发...

如何强制所有流量使用 HTTPS一网上用户

如何强制所有流量使用HTTPS一网上用户使用.htaccess强制流量到https的最常见方法可能是使用.htaccess重定向请求。.htaccess是一个简单的文本文件,简称为“.h...

https和http的区别(https和http有何区别)

“HTTPS和HTTP都是数据传输的应用层协议,区别在于HTTPS比HTTP安全”。区别在哪里,我们接着往下看:...

快码住!带你十分钟搞懂HTTP与HTTPS协议及请求的区别

什么是协议?网络协议是计算机之间为了实现网络通信从而达成的一种“约定”或“规则”,正是因为这个“规则”的存在,不同厂商的生产设备、及不同操作系统组成的计算机之间,才可以实现通信。简单来说,计算机与网络...

简述HTTPS工作原理(简述https原理,以及与http的区别)

https是在http协议的基础上加了一层SSL(由网景公司开发),加密由ssl实现,它的目的是为用户提供对网站服务器的身份认证(需要CA),以至于保护交换数据的隐私和完整性,原理如图示。1、客户端发...

21、HTTPS 有几次握手和挥手?HTTPS 的原理什么是(高薪 常问)

HTTPS是3次握手和4次挥手,和HTTP是一样的。HTTPS的原理...

一次安全可靠的通信——HTTPS原理

为什么HTTPS协议就比HTTP安全呢?一次安全可靠的通信应该包含什么东西呢,这篇文章我会尝试讲清楚这些细节。Alice与Bob的通信...

为什么有的网站没有使用https(为什么有的网站点不开)

有的网站没有使用HTTPS的原因可能涉及多个方面,以下是.com、.top域名的一些见解:服务器性能限制:HTTPS使用公钥加密和私钥解密技术,这要求服务器具备足够的计算能力来处理加解密操作。如果服务...

HTTPS是什么?加密原理和证书。SSL/TLS握手过程

秘钥的产生过程非对称加密...

图解HTTPS「转」(图解http 完整版 彩色版 pdf)

我们都知道HTTPS能够加密信息,以免敏感信息被第三方获取。所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议。...

HTTP 和 HTTPS 有何不同?一文带你全面了解

随着互联网时代的高速发展,Web服务器和客户端之间的安全通信需求也越来越高。HTTP和HTTPS是两种广泛使用的Web通信协议。本文将介绍HTTP和HTTPS的区别,并探讨为什么HTTPS已成为We...

HTTP与HTTPS的区别,详细介绍(http与https有什么区别)

HTTP与HTTPS介绍超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的...

一文让你轻松掌握 HTTPS(https详解)

一文让你轻松掌握HTTPS原文作者:UC国际研发泽原写在最前:欢迎你来到“UC国际技术”公众号,我们将为大家提供与客户端、服务端、算法、测试、数据、前端等相关的高质量技术文章,不限于原创与翻译。...

如何在Spring Boot应用程序上启用HTTPS?

HTTPS是HTTP的安全版本,旨在提供传输层安全性(TLS)[安全套接字层(SSL)的后继产品],这是地址栏中的挂锁图标,用于在Web服务器和浏览器之间建立加密连接。HTTPS加密每个数据包以安全方...

一文彻底搞明白Http以及Https(http0)

早期以信息发布为主的Web1.0时代,HTTP已可以满足绝大部分需要。证书费用、服务器的计算资源都比较昂贵,作为HTTP安全扩展的HTTPS,通常只应用在登录、交易等少数环境中。但随着越来越多的重要...

取消回复欢迎 发表评论: