Java线程同步方式记录

Java Se相关测试题(偏线程、集合)含答案及详解 Java Se相关测试题(偏线程、集合)(简答、编程)含答案及详解一、选择、简答题二、编程题 (编程答案有很多思路,实现方式不同,如果有不同见解可打在评论区或私信) 一、选择、简答题 1、public class Test{ public static String stringReplace(String text) { return text.replace('j', 'L'); } public static StringBuffer bufferReplace(StringB 阅读详情
  • 
    jvm对java多线程做了很多优化,这里对java线程的多个同步方式做一个记录。
    
    ​​​​synchronized关键字

被该关键字修饰的方法块或方法执行时,会先尝试获取锁,如果其它线程已获取锁,则等待线程释放锁,多个线程等待锁时,不是按照等待获取锁的线程顺序来获取锁,这是一个重量级锁,底层会使用monitorenter、monitorexit指令,jvm会采取一定的优化措施

private void incr(){
        synchronized (SyncService.class){
            int i=10;
            i++;
            _num++;
        }
    }

    public void noSync() throws InterruptedException {
        Thread[] ths=new Thread[THREAD_COUNT];
        for(int i=0;i<THREAD_COUNT;i++){
            ths[i]=new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int i1=0;i1<1000;i1++){
                        incr();
                    }
                    cd.countDown();
                }
            });
            ths[i].start();
        }
        cd.await();
        System.out.println(_num);
    }

 

  • ReentrantLock

可重入锁,和synchronized关键字一样属于重量级锁,它更灵活一点,可以控制加锁、解锁的时机,已获取锁的线程可以重复获取锁,但必须以同样的次数来解锁。

private ReentrantLock _lock=new ReentrantLock();

    private void incr(){
        try{
            _lock.lock();
            _lock.lock();
            int i=10;
            i++;
            _num++;
        }finally {
            _lock.unlock();
            _lock.unlock();
        }
    }

    public void noSync() throws InterruptedException {
        Thread[] ths=new Thread[THREAD_COUNT];
        for(int i=0;i<THREAD_COUNT;i++){
            ths[i]=new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int i1=0;i1<1000;i1++){
                        incr();
                    }
                    cd.countDown();
                }
            });
            ths[i].start();
        }
        cd.await();
        System.out.println(_num);
    }
  • ReentrantReadWriteLock 读写锁,共享读互斥写,可以多个线程获取读锁,但写锁同一时刻只能一个线程拥有,当有线程拥有读锁时,获取写锁的线程阻塞,当写锁加锁时,获取读锁的线程阻塞等待。

    适用于读多于写的场景下。

private ReentrantReadWriteLock _rwLock=new ReentrantReadWriteLock();
    private void incr(){
        try{
            _rwLock.writeLock().lock();
            int i=10;
            i++;
            _num++;
        }finally {
            _rwLock.writeLock().unlock();
        }
    }

    private void readNum(){
        try{
            Thread.sleep(1000);
            _rwLock.readLock().lock();
            System.out.println(String.format("threadid %d num %d",Thread.currentThread().getId(),_num));
        }catch (Exception ex){
            ex.printStackTrace();
        }
        finally {
            _rwLock.readLock().unlock();
        }
    }

    public void noSync() throws InterruptedException {
        Thread[] ths=new Thread[THREAD_COUNT];
        for(int i=0;i<THREAD_COUNT;i++){
            ths[i]=new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int i1=0;i1<1000;i1++){
                        readNum();
                    }
                    cd.countDown();
                }
            });
            ths[i].start();
        }

        while (true){
            Thread.sleep(2000);
            System.out.println("开始写");
            incr();
            System.out.println("结束写");
        }
    }
  • StampedLock 乐观锁,同读写锁区别在于,读的同时允许写,但这样就造成了共享资源的不一致,所以需要在读操作里判断是否有写操作,如果有则使用悲观读锁,来重新读取一次。

private double x, y;
   private final StampedLock sl = new StampedLock();

   void move(double deltaX, double deltaY) { 
     long stamp = sl.writeLock(); //获取写锁
     try {
       x += deltaX;
       y += deltaY;
     } finally {
       sl.unlockWrite(stamp);
     }
   }

   double distanceFromOrigin() { // A read-only method
     long stamp = sl.tryOptimisticRead(); //获取乐观读锁,不阻塞写锁的获取
     double currentX = x, currentY = y;
     //根据时间量stamp判断读取后,数据是否被改写,如果是则重新获取悲观读锁,重新读取一次。
     if (!sl.validate(stamp)) {
        stamp = sl.readLock();
        try {
          currentX = x;
          currentY = y;
        } finally {
           sl.unlockRead(stamp);
        }
     }
     return Math.sqrt(currentX * currentX + currentY * currentY);
   }
  • Semaphore 信号量,可以控制共享资源被多个线程访问的数量。
private final Semaphore available = new Semaphore(3, true); //初始化信号量3
private void readNum(){
    try{
        available.acquire(); //获取锁,成功则信号量减1
        System.out.println(String.format("threadid %d num %d",Thread.currentThread().getId(),_num));
        Thread.sleep(3000);
    }catch (Exception ex){
        ex.printStackTrace();
    }
    finally {
        available.release(); //释放锁,成功则信号量加1
    }
}
  • CountDownLatch 计数器,初始化一个数量,调用await在数量减少为0前将等待,用于任务依赖于其它任务完成后的场景。
private CountDownLatch cd=new CountDownLatch(THREAD_COUNT);
    public void noSync() throws InterruptedException {
        Thread[] ths=new Thread[THREAD_COUNT];
        for(int i=0;i<THREAD_COUNT;i++){
            ths[i]=new Thread(new Runnable() {
                @Override
                public void run() {
                    readNum();
                    cd.countDown(); //任务完成后计数器减1
                }
            });
            ths[i].start();
        }
        cd.await(); //等待计数器为0
    }
  • CyclicBarrier 屏障,和CountDownLatch类似,提供一个屏障(条件点),当所有线程到达该点时,一起执行。
  • private CyclicBarrier cb=new CyclicBarrier(THREAD_COUNT, new Runnable() {
            @Override
            public void run() {
                System.out.println(String.format("所有线程已到达3秒后一起执行"));
                try{
                    Thread.sleep(3000);
                }catch (Exception ex){
                    ex.printStackTrace();
                }
            }
        });
        public void noSync() throws InterruptedException {
            Thread[] ths=new Thread[THREAD_COUNT];
            for(int i=0;i<THREAD_COUNT;i++){
                ths[i]=new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(2000);
                            cb.await();//等待所有线程到位后执行后续代码
                            System.out.println(String.format("threadid %d",Thread.currentThread().getId()));
                        }catch (Exception ex){
                            ex.printStackTrace();
                        }
                        cd.countDown(); //任务完成后计数器减1
                    }
                });
                ths[i].start();
            }
            cd.await(); //等待计数器为0
        }

     

【程序员快速复习系列】Java多线程(2-线程同步、竞争、协作) 程序员面试本是一件再平常不过的事情,记得刚毕业的时候面试题背的滚瓜烂熟。但是在职程序员面试却是另一回事了,我们往往没有太多时间复习,特别是大龄程序员,工作日忙于工作,周末还要照顾家庭,一旦面临被优化的风险就很被动,难以在短时间内复习并找到工作。不要问我是怎么知道的,都是切身体会,在复习的过程中我也走了不少弯路,所幸最终结果令自己满意。为了不让和我一样的程序员遇到同样的问题,我打算写这一系列的文章,这些文章不会像其他面经一般大而全,这些文章仅记录我在复习过程中认为重要的知识点,如果能帮助到你就太好了。 阅读详情

相关推荐

Android SSL证书固定实战:原理、方案与避坑指南

SSL/TLS协议是保障网络通信安全的基石,其核心原理是通过非对称加密和数字证书实现身份认证与数据加密。在移动应用开发中,为了防止中间人攻击,证书固定技术应运而生,它通过将服务器证书或公钥的哈希值预置在应用内,强制校验服务器身份,从而大幅提升通信链路的安全性。这一技术对于金融、电商等高安全要求场景尤为重要。本文聚焦Android平台,深入解析SPKI固定、Network Security Configuration与OkHttp CertificatePinner等主流方案,并针对证书更新、调试兼容等常见痛

weixin_33935636的博客 402

java入门

语法

william的专栏 218

内网Linux服务器离线安装python包

3、将下载的依赖包和requirements.txt 拷贝到内网主机,依赖包和requirements.txt放同一级目录,进入该目录,运行指令。其实还有个更加方便的办法,联网主机装个与内网主机一样环境的虚拟机,在虚拟机中下载py包,拷贝到内网主机后就能直接安装了,省去手动下载py包的步骤。简单记录下最近遇到的一个小问题,内网主机没有内网源,处于无互联网状态,安装python包只能通过联网主机下载好后拷贝到内网主机。由于内网主机安装了多个版本的python,为了防止搞错,使用这种方式来调用pip安装。

cyc头发还挺多的博客 650

Java高级核心技术

本文总结了Java高级核心技术五大领域的核心知识点:1)JVM与性能优化:重点分析元空间与永久代的区别、内存泄漏诊断及GC机制;2)并发编程:涵盖JMM模型、锁机制对比、虚拟线程及线程池;3)集合框架:解析HashMap并发安全实现及各类集合特性差异;4)Java新特性:包括Record模式、密封类等语法糖的应用;5)设计模式:着重单例、工厂模式的实现与适用场景。这些内容不仅涉及原理层面的深入理解,更强调实际调优经验和生产问题的解决方案,是Java高级开发必备的核心能力体系。

qq_35216414的博客 837

智能体在车联网中的应用:第19天 智能体理论与初步实践 D30:阶段小结——在SUMO中使用TraCI控制预编程智能体

本文介绍了如何将强化学习从算法仿真迁移到交通系统实践,重点讲解了SUMO微观交通仿真平台与TraCI实时控制接口的架构。通过构建一个预编程驾驶智能体,演示了车辆从起点到目标点的导航控制。文章详细解析了TraCI的双向通信机制和事件驱动模型,对比了其与传统RL环境的差异,并提供了完整的Python实现框架,包括路网配置、车辆控制和基于向量场的导航逻辑。该实践为后续开发高级学习型交通智能体奠定了基础。

IT深耕十余载,大道之简 1478

电池建模 004- Battery (Table-Based)表格化电池模型入门学习

对于 Battery (Table-Based) 模块,提供了多种内置参数。该预参数化数据允许您将模块设置为代表特定供应商的组件。这些电池的参数化可以与制造数据表中的放电曲线相匹配。要加载预定义的参数化,双击 Battery (Table-Based) 模块,点击 Selected part 参数中的 超链接,然后在块参数化管理器窗口中,从可用组件列表中选择所需部件。 (默认)选项用于参数化模块,以代表特定供应商的组件。

qq_63860930的博客 2734

Java开发必会技术!java爬虫入门实战

一面 正式批(别看了都是正式批,提前批就没让我面!)一面。面试时间 08-18,19:53 - 21:08,全程1个小时15分钟。涉及内容:项目、网络、数据库、算法题 1. 自我介绍 2. 项目中的有挑战的点(问了大概有五六个问题) 3. 问了下本科啥专业的,学过哪些课程(主要是为了下面面试问题的内容,我说了操作系统和计算机网络学的时间久了,结果就挑着问hhh,佛了) 4. 你知道 DNS 协议嘛?描述一下从输入域名到显示的过程(从 DNS 解析到 HTTP 链接建立到内容返回浏览器渲染) 5. 你刚提到了

m0_56835488的博客 195

Open3D KD-tree的使用【2025最新版】

Open3d使用FLANN构建KDTree以便进行快速最近邻检索。博客长期更新,本文最近一次更新时间为:2025年1月1日,代码已同步更新至Open3D 0.18.0版本。

点云侠的博客 40万+

JAVA多线程详解(超详细)

文章目录1. 线程概述1.1 什么是进程1.2 什么是线程1.3 进程和线程的区别1.4 线程的组成1.5 线程的特点2. 线程的创建2.1 创建线程(一)2.2 获取和修改线程名称2.3 一个线程小案例2.4 创建线程(二)2.5 Runnable小案例3. 线程的基本状态4. 线程常用方法5. 线程安全5.1 同步方式(1)5.2 线程基本状态(源码补充)5.3 同步方式(2)5.4 经典问题(死锁)5.5 线程通信5.6 经典问题(生产者消费者)6. 线程池6.1 线程池概念6.2 线程池原理6.3

weixin_41121133的博客 5415

【MATLAB代码】基于水声通信(ACOMMS)下的到达时间差(TDOA)定位的AUV自主导航例程,附完整代码

水下AUV导航系统仿真研究 本研究基于到达时间差(TDOA)技术实现了水下自主航行器(AUV)的三维导航仿真系统。系统采用四个声学信标作为定位基准,通过TDOA测量数据迭代求解AUV位置。仿真结果表明: 导航性能:系统能够有效跟踪AUV从起点(30,30,-20)到目标点(70,70,-20)的航行轨迹,定位误差保持在合理范围内。 误差分析:定位误差变化曲线显示系统具有稳定的定位精度,平均误差为0.5米左右。 技术特点:采用两步最小二乘迭代算法求解非线性TDOA方程,提高了定位精度和计算效率。 该仿真系统为

985工科博士毕业,专攻定位、导航和滤波等算法研究。从业10年,主要使用MATLAB 320

AI测试实战:手把手教你做LLM(大模型)性能测试「含完整代码」

大模型API性能测试是评估模型服务响应能力、吞吐量和资源效率的关键手段。核心指标包括总响应时间、吐字率、首token延迟、输入/输出tokens数量、QPM等。测试流程涵盖构造负载、并发请求、数据采集和指标计算。优化建议针对吐字率低、首token延迟高、QPM偏低等问题,从模型、硬件、系统等多层面提出解决方案。

blues_C的博客 1430

线程间的通信、同步方式、进程间通信方式

转载:http://www.jianshu.com/p/9218692cb2091、线程间的通信方式 使用全局变量 主要由于多个线程可能更改全局变量,因此全局变量最好声明为volatile。 使用消息队列实现通信 在Windows程序设计中,每一个线程都可以拥有自己的消息队列(UI线程默认自带消息队列和消息循环,工作线程需要手动实现消息循环),因此可以采用消息进行线程间通信sendMessage

西瓜游侠的博客 983

鸿蒙系统开发工程师:核心技术解析与深度面试指南

摘要: 鸿蒙系统开发工程师需具备底层驱动开发、系统移植优化及分布式架构能力。核心职责包括硬件适配(Bootloader、内核移植、HDF驱动开发)、性能调优(启动加速、功耗管理)及稳定性保障。技术要求涵盖C/C++编程、Linux内核机制、鸿蒙架构(HDF、分布式服务)及ArkTS/ArkUI基础。面试重点考察系统移植流程(如ARM板适配)、驱动开发(I2C/Display)、性能优化手段及内存/同步机制的应用。

郑伟强dev的专栏 430

Java - 线程同步方式

概念 同步异步 消息通信机制 同步:发出调用之后,在没有得到结果之前,该调用不返回。调用者主动等待调用结果。异步:发出调用之后,该调用直接返回,无结果。被调用者通过状态、通知进行反馈,或者通过回调函数处理这个调用。 阻塞非阻塞 调用者等待调用返回值时的状态 阻塞:调用结果返回之前,当前线程[ 调用者]会被挂起非阻塞:不能立刻得到结果之前,调用者线程不会被阻塞

PeersLee的博客 631

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

JAVA线程的同步机制

引言

weixin_40194150的博客 228

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

深入浅出Java并发线程阻塞唤醒类LockSupport

经过上面的分析得出结论 unpark 的语义明确为「使线程持有许可证」,park 的语义明确为「消费线程持有的许可」,所以 unpark 与 park 的执行顺序没有强制要求,只要控制好使用的线程即可,LockSupport 的设计思路是通过许可证来实现的,就像汽车上高速公路,入口处要获取通行卡,出口处要交出通行卡,如果没有通行卡你就无法出站,当然你可以选择补一张通行卡。最后再补充下 park 的注意点,因 park 阻塞的线程不仅仅会被 unpark 唤醒,还可能会被线程中断(thread 线程调用。

2302_79432188的博客 460

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

java 线程同步_Java编程核心技术之——线程同步

1、线程同步背景程序在运行过程中,会将运算需要的数据(如:常量、变量等)从物理内存复制一份到CPU的高速缓存中,这样CPU就可以直接在高速缓存中读写数据、进行运算,最后当运算结束时、再将高速缓存中的数据刷新到物理内存;多线程访问同一变量(或内存)时,由于每个线程都有自己独立的高速缓存(对应一个或多个CPU),这样每个线程对应的高速缓存中的数据刷新到物理内存时就有可能相互覆盖、造成混乱,这就是典型的...

weixin_39611049的博客 153

记录一次Java面试

面试题 没有仔细寻找答案,,,,,,, JVM虚拟机的内存分配 Java的GC垃圾回收和算法 垃圾回收机制的意义 内存泄露:指该内存空间使用完毕后未回收,在不涉及复杂数据结构的一般情况下,java的内存泄露表现为一个内存对象的生命周期超出了程序需要它的时间长度,我们有是也将其称为“对象游离”。 垃圾回收机制的算法 java语言规范没有明确的说明JVM 使用哪种垃圾回收算法,但是任何一...

毕九生的博客 219

【深度解析】从JVM视角看Java线程与锁优化

fill:#333;color:#333;color:#333;fill:none;监控预警定期jstack分析设置锁超时时间监控线程阻塞时间锁优化策略优先选择无锁设计减小锁粒度缩短锁持有时间使用读写分离选择合适并发容器CAS操作原子变量拆分大锁为小锁尽快释放锁资源图7: 锁优化最佳实践总结优先考虑无锁方案(原子类、并发容器)尽量减小同步范围和使用细粒度锁监控和分析生产环境的锁竞争情况根据实际场景选择合适的锁策略。

✨ 欢迎来唠嗑、切磋、一起成长!👋 1192

常见问题记录

当提交任务的速度大于处理任务的速度时,每次提交一个任务,就必然会创建一个线程。由于空闲 60 秒的线程会被终止,长时间保持空闲的 CachedThreadPool 不会占用任何资源。FixedThreadPool 适用于处理CPU密集型的任务,确保CPU在长期被工作线程使用的情况下,尽可能的少的分配线程,即适用执行长期的任务。提交任务---核心线程池是否已满---队列是否已满---线程池是否已满---饱和策略。适用于串行执行任务的场景,一个任务一个任务地执行。用于并发执行大量短期的小任务。

weixin_35837339的博客 1859

Java多线程与线程池技术详解(二)

Java 提供的一种内置同步机制,用于确保多个线程在访问共享资源时不会发生冲突。通过使用关键字,可以将代码段或方法标记为同步区域,使得同一时刻只有一个线程能够执行该区域的代码,从而保证了数据的一致性和完整性。概览)

物联网工程专业 - 软硬兼修 1385

Java 多线程(Java线程间的通信)

Java线程间的通信 锁与同步方式 锁概念:在Java中,锁的概念都是基于对象的,所以我们⼜经常称它为对象锁。 线程和锁的关系:⼀个锁同⼀时间只能被⼀个线程持有。也就是说,⼀个锁如果和⼀个线程持有,那其他线程如果需要得到这个锁,就得等这个线程和这个锁释放。 Java的集中常见锁类型: 锁名称 说明 内置锁 每一个java对象都可以用作同步的锁(monitor锁) 可重入锁 当一个线程得到一个对象锁后,再次请求此对象锁时是可以再次得到该对象的锁。这也证明在一个ReentrantLock/S

Arnold的博客 332

Java 多线程一

多个线程同时访问一个共享资源且存在修改该资源的操作,可能会发生数据冲突问题,但是执行读操作不会发生数据冲突。多个线程并发同时访问共享资源存在修改共享资源。

weixin_43955543的博客 166

java异步记录日志到jms,Log4j的AsyncAppender能否提升性能?

近日在写多线程方面的东西,需要对多线程进行日志监控就重新翻出了log4j,看到了log4j下居然还有一个AsyncAppender,异步记日志?觉得挺不错,网上搜了一下也有一些讨论,JavaEye上也有很多讨论。但是这个AsyncAppender到底能否提升日志性能呢?我们还是先看看log4j本身文档里的性能测试说明吧,详细测试数据见如下URL:http://www.ingrid.org/jaja...

weixin_39600823的博客 307

并发编程(16)——基于同步方式的线程安全的查找表

哈希表相比上面两种方式无疑是更好的选择,哈希表有很多个桶(哈希函数生成的值,我们这里用链表的方式存储桶中值),每个关键字(key)都属于一个桶,因为每个桶都占据一块独立的内存,所以我们可以为每个桶单独的施加独立的锁。,在同一时间有且仅有一个线程可以修改共享数据(因为C++标准库提供的链表的增删改查是通过同一个互斥量实现的,锁粒度不够精细),我们需要像上一节实现队列一样,自定义一个链表结构,通过多个锁来为增删查改进行保护,每个操作有自己独立的锁,实现写操作的并发。这里不多过叙述,可以自行查找相关的资源。

m0_63086198的博客 1152

java线程池如何实现_java线程池如何实现方法?和线程区别在哪?

java中关于线程池与线程的知识也是非常复杂的,这往往需要人们花费大量的精力与时间去分清他们之间的区别与联系。今天就主要来介绍一下实现线程池的方法,同时会着重区别与线程。一起来了解一下吧。首先我们需要知道的是,线程池的实现方法与线程是不一样的。初始化时在线程池里的线程为0。当进程需要一个线程时,创建一个线程,由此线程执行用户的方法.需要注意的是,此线程执行完后并不立即销毁,而是挂起等待,如果有其他...

weixin_39579726的博客 125
上一篇: Java9的Module机制研究
下一篇: Linux 读写进程物理内存
IT回忆录
博客等级 码龄16年 42粉丝 100原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值