多线程-进阶2

news2024/9/20 9:41:31

 博主主页: 码农派大星.

    数据结构专栏:Java数据结构

 数据库专栏:MySQL数据库

JavaEE专栏:JavaEE

关注博主带你了解更多数据结构知识

1.CAS

1.1CAS全称:Compare and swap

比较内存和cpu寄存器中的内容,如果发现相同,就进行交换(交换的是内存和另一个寄存器的内容)

一个内存的数据 和 两个寄存器中的数据进行操作(寄存器1和寄存器2)

此处的"交换"实际上就是赋值

比较内存和寄存器1中的值,是否相等,如果不等,就无事发生,如果相等,就交换内存和寄存器2的值(此处只关心内存交换后的内容,不关心寄存器2交换后的内容)

因此CAS就能编写多线程代码,"无锁化编程"

CAS具体使用场景

1)基于CAS实现原子类 都是线程安全

import java.util.concurrent.atomic.AtomicInteger;
public class Main5 {
private static AtomicInteger count = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            for (int i = 0; i <50000 ; i++) {
             count.getAndIncrement();//count++
//           count.incrementAndGet();//++count
//           count.getAndDecrement();//count--
//           count.decrementAndGet();//--count
     //      count.getAndAdd(10);//count+= 10
            }
        });
        Thread t2 = new Thread(()->{
            for (int i = 0; i <50000 ; i++) {
                count.getAndIncrement();//count++
              /*  count.incrementAndGet();//++count
                count.getAndDecrement();//count--
                count.decrementAndGet();//--count*/
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t1.join();
        System.out.println(count.get());
    }
}

2.Callable接口

Callable 接口也是创建线程的一种方式。相当于把线性封装了一个返回值。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Main {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 0; i < 1000; i++) {
                    sum += i;

                }
                return sum;
            }
        };
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread t = new Thread(futureTask);
        t.start();
        System.out.println(futureTask.get());


    }
}

3.创建线程的方式:

1.直接继承Thead类

2.使用Runnable

3.使用Callable

4.使用lambda

5.使用线程池

4.ReentrantLock

4.1synchroniazed与ReentrantLock区别

1)大多是情况下使用synchronized,属于关键字(底层是通过JVM的c++代码实现的)

ReentrantLock则是标准库提供的类,通过Java代码实现的

2)synchronized通过代码块控制加锁解锁,ReentrantLock通过调用lock unlock方式来完成 unlock可能会遗漏

3)ReentrantLock 提供了tryLock这样的加锁风格

前面介绍的加锁,都是发现锁被别人占用了,就阻塞等待

tryLock在加锁失败的时候,不会阻塞,而是返回,通过返回值来反馈是加锁成功还是失败

4)1Reentrantlock提供了公平锁的实现

默认是非公平的,可以在构造方法中,传入参数,设定成公平的

5)Reentrantlock还提供了功能更强的功能"等待通知机制"

基于Condition类,能力要比wait notify更强一些.

import java.util.concurrent.locks.ReentrantLock;

public class Main2 {
    public static int count = 0;
    public static void main(String[] args) throws InterruptedException {
        ReentrantLock locker = new ReentrantLock();
        Thread t1 = new Thread(()->{
            for (int i = 0; i < 50000; i++) {
                locker.lock();
                count++;
                locker.unlock();
            }
        });
        Thread t2 = new Thread(()->{
            for (int i = 0; i <50000 ; i++) {
                locker.lock();
                count++;
                locker.unlock();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(count);
    }



}

5.信号量Semaphore

import java.util.concurrent.Semaphore;

public class Main3 {
    public static void main(String[] args) throws InterruptedException {
        Semaphore semaphore =new Semaphore(3);//可硬资源数,计数器初始值

        semaphore.acquire();
        System.out.println("申请一个资源");
        semaphore.acquire();
        System.out.println("申请一个资源");
        semaphore.acquire();
        System.out.println("申请一个资源");
        semaphore.release();
        System.out.println("释放一个资源");
        semaphore.acquire();
        System.out.println("申请一个资源");


    }


}

6.CountDownLatch

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main4 {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        //构造方法的数字,就是拆分出来的任务个数
        CountDownLatch countDownLatch =new CountDownLatch(20);

        for(int i = 0 ; i < 20;i++){
            int id = i;
            executorService.submit(()->{
                System.out.println("下载任务"+id+"开始执行");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("下载任务"+id+"结束任务");
                //完毕!!
                countDownLatch.countDown();
            });
        }

            //当countDownLatch收到20个"完成",所有的任务就完成了
 //await= allwait
            countDownLatch.await();

    }



}

借助CountDownLatch就能衡量出当前任务是否整体执行结束

7.线程安全的集合类

解决方案:

1)自己加锁

2)如果要使用ArraryList/LinkedList这样的结构

标准库中,提供了一个带锁的List

还可以使用CopyOnWrite集合类

写时拷贝的缺点:

1)无法应对,多个线程同时修改的情况

2)如果涉及到数据量很大,拷贝起来非常慢 

3)想多线程环境下使用队列

BlockingQueue

4)多线程环境下使用哈希表

Hashtable虽然是可选项

ConcurrentHashMap[推荐]

此处这个数据结构,相比于HashMa和Hashtable 来说,改进力度非常大的

1)优化了锁的粒度 

Hashtable的加锁,就是直接给put get 的方法加上synchronized,就是给this加锁

整个哈希表对象就是一把锁,任何一个针对这个哈希表的操作,都会触发锁竞争

ConcurrentHashMap则是给每个哈希表中的"链表" 进行加锁.(不是一把锁,而是多把锁)

上述设定方式,是可以保证线程安全的!!

其次可大大降低锁冲突的概率,只有同时进行两次修改,恰好在修改在同一链表元素上的时候,才会

触发锁竞争

2)ConcurrentHashMap引入了CAS原子操作.针对像修改了size这样的操作,直接借助CAS完成,才不会加锁

3)针对读操作,做了特殊处理 .上述的加锁,只是针对写操作,加锁

对于读操作,通过volatile以及一些精巧的代码实现,确保读操作,不会读到"修改一半的数据"

4)针对hash表的扩容,进行了特殊的优化

普通hash表的扩容,需要创建新的hash表,把元素搬过去

这一列操作,很有可能就在一次put中就完成了就会使这次put开销非常大,耗时非常长

ConcurrentHashMap进行了"化整为零" 不会在一次操作中,进行搬运所有数据而是一次搬运一部分,伺候每次操作,都会触发,一部分key的搬运,最终把所有的key都搬运完成

当新旧同时存在的时候

1)插入操作,直接插入到新空间中

2)查询/修改/删除/都需要同时查询旧的空间和新空间

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1957426.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《学会 SpringBoot · 参数校验》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

连锁美业门店收银系统Java源码-如何设置门店仓库自提时间?博弈美业实操

1. 门店仓库自提时间&#xff0c;是当客户在小程序上购买实物商品时&#xff0c;预约上门提货的时间 2. 门店仓库自提时间&#xff0c;需要由各门店&#xff08;店主、店长、店员&#xff09;在PAD上进行设置 ▶ 操作路径&#xff1a; • 第一步&#xff1a; 进入【我的】页…

怎么进行图片压缩?对图片文件的大小进行压缩的四个方法介绍

怎么进行图片压缩&#xff1f;图片压缩是一种常见的技术&#xff0c;用于减小图像文件的大小&#xff0c;同时尽可能地保持图像的视觉质量和细节。这一过程不仅适用于个人用户想要节省存储空间或提高网页加载速度&#xff0c;也对于专业摄影师、网站设计师和应用程序开发者来说…

【OceanBase诊断调优】—— clog盘满问题排查

背景 日志盘&#xff0c;即clog盘&#xff0c;是oceanbase中用于记录事务日志信息。在日常运行中其存储量会随着事务处理情况不断变化。在一些特殊场景下会出现clog盘占用量超过阈值的情况。4.x架构下的clog盘&#xff0c;日志盘进行了租户级拆分&#xff0c;意味着无法再以3.…

Redis缓存数据库进阶——Redis缓存数据同步问题(8)

Redis缓存使用问题 数据一致性 只要使用到缓存&#xff0c;无论是本地内存做缓存还是使用 redis 做缓存&#xff0c;那么就会存在数据同步的问题。 我以 Tomcat 向 MySQL 中写入和删改数据为例&#xff0c;来给你解释一下&#xff0c;数据的增删改操作具体是如何进行的。 我…

Java中的集合相关知识汇总

总结 Java集合 从数据结构可以分为&#xff1a;数组、Set、Map、队列、栈&#xff1b;从多线程安全可以分为线程安全与非线程安全的集合从关联关系可以总结如下(不包含多线程安全类)&#xff1a; 点线框表示接口&#xff1b; 折线框表示抽象类&#xff1b; 实线框表示实现类…

动态代理IP VS 静态代理IP,分别适合什么业务场景?

随着全球化进程的加深&#xff0c;使用IP代理服务的用户与日俱增。本文以“动态IP代理与静态IP代理”为探讨话题&#xff0c;对它们之间的区别、特点与应用场景作深度的对比分析。 一、含义上的区别 动态IP代理&#xff1a;互联网服务提供商&#xff08;ISP&#xff09;向用户…

Pytorch中reshape,view,transpose以及permute的详细原理及应用

在深度学习中&#xff0c;我们经常会遇到需要对张量进行形状变换的情况。PyTorch 提供了多种方法来改变张量的形状&#xff0c;包括 reshape, view, transpose和permute 。本文总结了其它博客的精华&#xff0c;详细介绍这些方法的原理和应用场景。 目录 一、张量的存储方式 …

使用 Elasticsearch 和 LlamaIndex 保护 RAG 中的敏感信息和 PII 信息

作者&#xff1a;来自 Elastic Srikanth Manvi 在这篇文章中&#xff0c;我们将研究在 RAG&#xff08;检索增强生成&#xff09;流程中使用公共 LLMs 时保护个人身份信息 (personal identifiable information - PII) 和敏感数据的方法。我们将探索使用开源库和正则表达式屏蔽 …

探索 Redis 不同集群架构的性能与应用

1. 引言 Redis的集群配置成为了提高数据可靠性和服务可用性的关键。本文将带领大家了解Redis的四种主要集群架构&#xff0c;并重点分析哨兵模式和Redis Cluster架构和优势。 2. Redis的四种集群架构 2.1 单实例Redis 使用单个 Redis 实例提供服务。适用于小规模应用&#…

C语言 #具有展开功能的排雷游戏

文章目录 前言 一、整个排雷游戏的思维梳理 二、整体代码分布布局 三、游戏主体逻辑实现--test.c 四、整个游戏头文件的引用以及函数的声明-- game.h 五、游戏功能的具体实现 -- game.c 六、老六版本 总结 前言 路漫漫其修远兮&#xff0c;吾将上下而求索。 一、整个排…

WEB前端开发中如何实现大文件上传?

大文件上传是个非常普遍的场景&#xff0c;在面试中也会经常被问到&#xff0c;大文件上传的实现思路和流程。在日常开发中&#xff0c;无论是云存储、视频分享平台还是企业级应用&#xff0c;大文件上传都是用户与服务器之间交互的重要环节。随着现代网络应用的日益复杂化&…

实况照片怎么转换成gif动图?分享5种方法!

在当今这个视觉为王的时代&#xff0c;静态的照片已经难以满足我们追求生动、有趣的表达需求。你是否也曾想过&#xff0c;将那些精彩瞬间的实况照片转换成动感十足的GIF动图&#xff0c;为社交分享增添一抹亮色&#xff1f;今天&#xff0c;就让我们一起来探索实况照片转换成G…

自闭症怎么才能摘帽?

作为星贝育园自闭症康复中心的老师&#xff0c;经常会有家长满怀期待又焦虑地问我&#xff1a;“自闭症怎么才能摘帽&#xff1f;”今天&#xff0c;我就来为大家详细说一说。 首先&#xff0c;我们要明确&#xff0c;自闭症的“摘帽”并非一蹴而就&#xff0c;而是一个…

U盘目录损坏:诊断、恢复与防范全解析

U盘目录损坏&#xff1a;数据安全的隐形挑战 在数字化生活日益普及的今天&#xff0c;U盘作为便携式数据存储设备&#xff0c;几乎成为了每个人工作、学习和生活中不可或缺的一部分。然而&#xff0c;U盘目录损坏问题却时常发生&#xff0c;给数据安全和用户体验带来了巨大挑战…

Python数值计算(10)

继续说多项式的数值及拟合&#xff0c;这次主要讨论关于多项式拟合的函数fit。定义如下&#xff1a; classmethod polynomial.polynomial.Polynomial.fit (x, y, deg, domainNone, rcondNone, fullFalse, wNone, windowNone, symbolx) Polynomial类下面有一个函数fit&#xf…

弄懂这5条深层逻辑,你也将通透豁达

01 如果正面解决不了问题&#xff0c;不妨试试从侧面或者反面进行解决。 比如&#xff0c;食堂的锅破了一个洞&#xff0c;如果你多次反映都没能解决破洞的问题&#xff0c;那不妨直接把锅捅穿&#xff0c;让锅没有办法使用&#xff0c;进而升级问题&#xff0c;把做饭不方便…

深入源码:解析SpotBugs (3) Detector

文章目录 OpcodeStackDetector常用套路调用栈visit code类检测方法检测代码行检测 前面的博客也提到过&#xff0c;Spotbugs 里面 Detector2 与 Detector&#xff0c;FindBugs2 与 FindBugs&#xff0c;GUI2与GUI&#xff0c;可以视为 Spotbugs 与 FindBugs 新老技术的碰撞&…

基于微信小程序+SpringBoot+Vue的网络安全科普系统(带1w+文档)

基于微信小程序SpringBootVue的网络安全科普系统(带1w文档) 基于微信小程序SpringBootVue的网络安全科普系统(带1w文档) 优质的网络安全科普系统不仅可以单纯的满足工作人员管理的日常工作需求&#xff0c;还可以满足用户的需求。可以降低工作人员的工作压力&#xff0c;提高效…

课程制作及教学体验革命,AI视频生成工具如何落地教育行业?

“大力发展数字教育”&#xff0c;这是2024年政府工作报告中提到的教育任务之一。同时&#xff0c;“人工智能”行动首次写入政府工作报告&#xff0c;意味着各行各业均有新的发展空间。那么&#xff0c;数字教育应该怎么做&#xff1f;此前&#xff0c;2024年全国教育工作会议…