java多线程实现同步的方式介绍

        在 Java 多线程编程中,同步是确保多个线程在访问共享资源时的正确性和一致性的重要机制。Java 提供了多种方式来实现线程同步,每种方式都有其特点和适用场景。以下是一些常见的同步方式及其特点和应用场景,以及简单的例子来说明它们的用法。


        1. `synchronized` 关键字
        特点
- 自动锁定和释放锁。
- 支持重入。
- 非公平锁。
- 只能用于实例方法和静态方法。
        应用场景
- 简单的同步需求,如同步方法或代码块。
        例子
        

public class SynchronizedExample {
    private int count = 0;
    public synchronized void increment() {
        count++;
    }
    public static void main(String[] args) {
        SynchronizedExample example = new SynchronizedExample();
        Thread t1 = new Thread(example::increment);
        Thread t2 = new Thread(example::increment);
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Count is: " + example.count);
    }
}


        
        2. `ReentrantLock` 类
         特点
- 需要手动锁定和解锁。
- 支持公平锁和非公平锁。
- 提供了比 `synchronized` 更灵活的锁定机制,如尝试锁定和条件等待。
        应用场景
- 需要更灵活锁定策略的场景,如尝试锁定或条件锁定。
        例子
        

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
    private Lock lock = new ReentrantLock();
    private int count = 0;
    public void increment() {
        lock.lock(); // 获取锁
        try {
            count++;
        } finally {
            lock.unlock(); // 释放锁
        }
    }
    public static void main(String[] args) {
        ReentrantLockExample example = new ReentrantLockExample();
        Thread t1 = new Thread(example::increment);
        Thread t2 = new Thread(example::increment);
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Count is: " + example.count);
    }
}


        
        3. `synchronized` 块
        特点
- 手动锁定和解锁。
- 支持重入。
- 非公平锁。
- 可以用于任何代码块。
        应用场景
- 当只需要同步代码块而不是整个方法时。
         例子
        

public class SynchronizedBlockExample {
    private int count = 0;
    private final Object lock = new Object();
    public void increment() {
        synchronized (lock) {
            count++;
        }
    }
    public static void main(String[] args) {
        SynchronizedBlockExample example = new SynchronizedBlockExample();
        Thread t1 = new Thread(example::increment);
        Thread t2 = new Thread(example::increment);
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Count is: " + example.count);
    }
}


        
        4. `volatile` 关键字
        特点
- 确保变量的可见性。
- 禁止指令重排。
- 只能用于变量,不能用于方法或代码块。
        应用场景
- 当多个线程只需要读写单个共享变量时。
        例子
        

public class VolatileExample {
    private volatile boolean flag= true;
    public void run() {
        while (flag) {
            System.out.println("Thread " + Thread.currentThread().getId() + " is running");
        }
    }
    public static void main(String[] args) throws InterruptedException {
        VolatileExample example = new VolatileExample();
        Thread t1 = new Thread(example::run);
        Thread t2 = new Thread(example::run);
        t1.start();
        t2.start();
        // 主线程休眠一段时间
        Thread.sleep(500);
        // 更改 flag 的值,使 t1 线程停止
        example.flag = false;
    }
}


        
        5. `AtomicInteger` 类
        特点
- 提供原子操作的整数类。
- 支持自增、自减等原子操作。
- 非公平锁。
        应用场景
- 当需要对整数进行原子操作时,如计数器。
         例子
        

import java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerExample {
    private AtomicInteger count = new AtomicInteger(0);
    public void increment() {
        count.incrementAndGet();
    }
    public static void main(String[] args) {
        AtomicIntegerExample example = new AtomicIntegerExample();
        Thread t1 = new Thread(example::increment);
        Thread t2 = new Thread(example::increment);
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Count is: " + example.count);
    }
}


        
        6. `CountDownLatch`、`CyclicBarrier` 和 `Semaphore` 类
        特点
- 这些类提供了线程间的协调和同步机制。
- `CountDownLatch` 允许一个或多个线程等待直到一组操作执行完毕。
- `CyclicBarrier` 允许一组线程相互等待,直到所有线程都达到某个屏障点。
- `Semaphore` 用于限制可以同时访问某个资源的最大线程数。
        应用场景
- 当需要线程间的协调和同步时,如多个线程完成任务后再执行下一步操作。
        例子(`CountDownLatch`)
        

import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
    private CountDownLatch latch = new CountDownLatch(2);
    public void performTask() {
        try {
            latch.await(); // 等待直到计数器下降到 0
            System.out.println("All tasks are completed");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        CountDownLatchExample example = new CountDownLatchExample();
        Thread t1 = new Thread(example::performTask);
        Thread t2 = new Thread(example::performTask);
        t1.start();
        t2.start();
        // 主线程休眠一段时间
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 计数器减到 0,使等待的线程继续执行
        example.latch.countDown();
        example.latch.countDown();
    }
}


        
        总结
        Java 提供了多种同步机制,包括 `synchronized` 关键字、`ReentrantLock`、`synchronized` 块、`volatile` 关键字、`AtomicInteger` 类以及 `CountDownLatch`、`CyclicBarrier` 和 `Semaphore` 类。每种机制都有其特点和适用场景。`synchronized` 关键字和 `ReentrantLock` 用于锁定代码块或方法,确保多线程对共享资源的独占访问。`volatile` 关键字用于确保变量的可见性和有序性。`AtomicInteger` 类提供了一种原子性的整数操作,适合于计数器等场景。而 `CountDownLatch`、`CyclicBarrier` 和 `Semaphore` 类则用于线程间的协调和同步,它们通过不同的机制来控制线程的执行流程。
        在实际应用中,选择合适的同步机制取决于具体的需求和场景。例如,如果你需要一个简单的锁机制,`synchronized` 关键字或 `ReentrantLock` 都是不错的选择。如果你需要对单个变量进行原子操作,`volatile` 关键字或 `AtomicInteger` 类会更加适合。而当你需要线程间的协调,例如等待所有线程完成任务后再继续执行时,`CountDownLatch`、`CyclicBarrier` 或 `Semaphore` 类会更加适合。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从零开始的LeetCode刷题日记:142.环形链表II

一.相关链接 视频链接:代码随想录:142.环形链表II 题目链接:142.环形链表II 二.心得体会 这道题是一道链表题,但他没有对头结点的操作,所以不用虚拟头结点。这道题要分两步进行,第一步是判断链表有没有环…

win11修改主机mac地址

很多时候,为了限制恶意的蹭流浪,除了分配固定的ip地址外,还限制mac地址。只有mac与ip一致,才能上网冲浪 网络适配器中修改 搜索“控制面板”打开 控制面板 > 网络和Internet > 网络和共享中心 >查看网络状态和任务>…

Redis什么这么快和Redis单线程模型和多线程

概述 1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1); 2、数据结构简单,对数据操作也简单,Redis中…

测试常用的Linux命令

前言 直接操作硬件 将把操作硬件的代码封装成系统调用,供程序员使用 虚拟机软件 可以模拟的具有完整硬件系统的功能 可以在虚拟机上安装不同的操作系统 Linux内核只有一个,发行版有很多种 内核来运行程序和管理像磁盘和打印机等硬件设备的核心程序 终端…

AD20中关于“Net(s) Not Found in Differential Pair”的解决方法

问题描述: Net(s) Not Found in Differential Pair:在差分对中找不到网络 我们需要在原理图设计中需要添加差分对,已经遵循了_N _P 结尾,也添加了差分对标识符,但是转换到PCB时显示差分对报错 解决方法&#xf…

GSA、GSEA、ssGSEA、GSVA用到的统计学知识点

文章目录 概率密度函数(probability density function,PDF)分布函数(Cumulative Distribution Function,CDF)核密度估计(KDE)经验累计分布函数(Empirical Cumulative Dis…

VUE_nuxt启动只能通过localhost访问,ip访问不到:问题解决

修改项目根目录下的 package.json "config": {"nuxt": {"host": "0.0.0.0","port": "3000"} } 这样项目启动后就可以通过ip进行访问了

目标检测论文模型笔记——YOLO系列

1. YOLOv1的核心思想: YOLOv1:使用整张图作为输入,直接在输出层回归bounding box和类别;(one-stage)Faster RCNN:使用用整张图作为输入,但整体采用了RCNN: proposalclas…

Facebook的社交未来:元宇宙时代的数字共融

引言: 随着科技的不断进步和社会的快速发展,人们对于社交网络的需求和期待也在不断演变。在这个数字化时代,元宇宙的概念逐渐引发了人们对社交体验的重新思考。作为全球最大的社交网络之一,Facebook正在积极探索元宇宙时代的社交…

低空经济20人|卓翼智能任雪峰:以技术驱动市场,引领无人机细分领域创新

作为国内系留无人机领域的领头羊企业,卓翼智能致力于提供智能无人系统解决方案。本期“低空经济20人”请到卓翼智能CEO任雪峰分享他对系留无人机研发应用的经验以及未来无人机行业生态发展的观点。 如今,无人机的应用场景逐渐广泛,在社会发展…

go go.mod file not found in current directory or any parent directory

场景: 安装好 liteide 之后创建了第一个 “hello world” 的golang 项目,却报了如下错误。 原因分析: go 的环境配置问题。与 golang 的包管理有关。 解决方案: 如果你是 Windows 系统,快捷键 “WinR”&#xff0c…

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK实现双快门采集两张曝光时间非常短的图像(C#)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK实现双快门采集两张曝光时间非常短的图像(C#) Baumer工业相机Baumer工业相机定序器功能的技术背景Baumer工业相机通过NEOAPI SDK使用定序器功能预期的相机动作技术限制定序器的工作原理 Baumer工业相机通过…

获取C语言语句对应的汇编码和机器指令

借助IDE的调试功能 以CodeBlocks为例,先设置断点,然后点击红色三角形调试。 然后选择Debug➡ Debugging Windows➡Disassembly 就可以看到了 使用命令行 在工程文件中,一般可以找到一个.o文件。如果没有,可以先在program.c的目录下…

【JavaEE初阶】 关于JVM垃圾回收

文章目录 🍃前言🎋死亡对象的判断算法🚩引用计数算法🚩可达性分析算法 🌳垃圾回收算法🚩标记-清除算法🚩复制算法🚩标记-整理算法🚩分代算法🎈哪些对象会进入…

在哪里可以下载大自然短视频素材?大自然短视频素材网分享

如果你想要制作短视频但又担心找不到那些让人心旷神怡的大自然素材,别急,我这就给你安利几个可以下载到高清、无水印的大自然短视频素材的网站。这样,你不仅能让作品视觉效果大大提升,还能让观众感受到大自然的魅力,一…

C语言之指针习题一

1. 解析:全选 2. 解析:A.当内存空间释放后,指针将指向其他的区域,成为野指针 3. 解析:B,assert只会在调试模式(debug)下使用,release不会使用 4. 解析: A…

【CSP试题回顾】202109-1-数组推导

CSP-202109-1-数组推导 解题代码 #include<iostream> #include<vector> #include<algorithm> using namespace std;long long maxSum, minSum;int main() { int n;cin >> n;vector<int>B(n);for (auto& it : B){cin >> it;maxSum …

day38 动态规划part1

509. 斐波那契数 简单 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a; F(0) 0&#xff0c;F(1) 1 F(n) F(n - 1) F(n - 2)&#xff0c;…

PR:添加MTV动态歌词

MTV的歌词效果如下&#xff1a; 1.用文字工具编辑歌词&#xff0c;选择合适的字体 2.点中素材&#xff0c;按住Alt键向上拖拽复制一份 3.文字填充色选择蓝色&#xff0c;描边选择白色加粗 4.添加不透明度蒙版&#xff0c;拖拽至歌词前面 5.打开蒙版路径前的秒表 6.在歌词结尾处…

C语言实现回调函数

C语言实现回调函数 一、回调函数概念1.1 什么叫函数指针 二、回调函数案例 一、回调函数概念 回调函数就是一个被作为参数传递的函数。在C语言中&#xff0c;回调函数只能使用函数指针实现&#xff0c;在C、Python、ECMAScript等更现代的编程语言中还可以使用仿函数或匿名函数…