java中的线程同步

Java中的多线程与同步 一、进程与线程          进程是可并发执行的程序在一个数据集上的一次执行过程,它是系统进行资源分配的基本单位。          线程为进程所有,作为调度执行的基本单位,一个进程可以有一个或多个线程,他们共享所属进程所拥有的资源。 二、为什么要引入进程与线程         要探索这个问题答案之前,需要先了解并发执行。并发执行是为了增强计算机系统的处理能力和提高资源利用率, 阅读详情

java中多线程的同步依靠的是对象锁机制,synchronized关键字的背后就是利用了封锁来实现对共享资源的互斥访问。

下面以一个简单的实例来进行对比分析。实例要完成的工作非常简单,就是创建10个线程,每个线程都打印从0到99这100个数字,
我们希望线程之间不会出现交叉乱序打印,而是顺序地打印。

先来看第一段代码,这里我们在run()方法中加入了synchronized关键字,希望能对run方法进行互斥访问,但结果并不如我们希望那样,
这是因为这里synchronized锁住的是this对象,即当前运行线程对象本身。代码中创建了10个线程,而每个线程都持有this对象的对象锁,这不能实现线程的同步。

代码
package com.thread.test;

class MyThread implements java.lang.Runnable
{
    private int threadId;
   
    public MyThread(int id)
    {
        this.threadId = id;
    }
   
    @Override
    public synchronized void run()
    {
        for (int i = 0; i < 100; ++i)
        {
            System.out.println("Thread ID: " + this.threadId + " : " + i);
        }
    }
}
public class ThreadDemo
{
/**
* @param args
* @throws InterruptedException
*/
    public static void main(String[] args) throws InterruptedException
    {
        for (int i = 0; i < 10; ++i)
        {
            new Thread(new MyThread(i)).start();
            Thread.sleep(1);
        }
    }
}

从上述代码段可以得知,要想实现线程的同步,则这些线程必须去竞争一个唯一的共享的对象锁。

基于这种思想,我们将第一段代码修改如下所示,在创建启动线程之前,先创建一个线程之间竞争使用的Object对象,
然后将这个Object对象的引用传递给每一个线程对象的lock成员变量。这样一来,每个线程的lock成员都指向同一个Object对象。
我们在run方法中,对lock对象使用synchronzied块进行局部封锁,这样就可以让线程去竞争这个唯一的共享的对象锁,从而实现同步。

代码
package com.thread.test;

class MyThread implements java.lang.Runnable
{
    private int threadId;
    private Object lock;
    public MyThread(int id, Object obj)
    {
        this.threadId = id;
        this.lock = obj;
    }
    @Override
    public void run()
    {
        synchronized(lock)
        {
            for (int i = 0; i < 100; ++i)
            {
                System.out.println("Thread ID: " + this.threadId + " : " + i);
            }
        }
    }
}  

public class ThreadDemo
{
/**
* @param args
* @throws InterruptedException
*/
    public static void main(String[] args) throws InterruptedException
    {
        Object obj = new Object();
        for (int i = 0; i < 10; ++i)
        {
            new Thread(new MyThread(i, obj)).start();
            Thread.sleep(1);
        }
    }
}

从第二段代码可知,同步的关键是多个线程对象竞争同一个共享资源即可,上面的代码中是通过外部创建共享资源,然后传递到线程中来实现。
我们也可以利用类成员变量被所有类的实例所共享这一特性,因此可以将lock用静态成员对象来实现,代码如下所示:

代码
package com.thread.test;

class MyThread implements java.lang.Runnable
{
    private int threadId;
    private static Object lock = new Object();
    public MyThread(int id)
    {
        this.threadId = id;
    }
   
    @Override
    public void run()
    {
        synchronized(lock)
        {
            for (int i = 0; i < 100; ++i)
            {
                System.out.println("Thread ID: " + this.threadId + " : " + i);
            }
        }
    }
}
public class ThreadDemo
{
/**
* @param args
* @throws InterruptedException
*/
    public static void main(String[] args) throws InterruptedException
    {
        for (int i = 0; i < 10; ++i)
        {
            new Thread(new MyThread(i)).start();
            Thread.sleep(1);
        }
    }
}

再来看第一段代码,实例方法中加入sychronized关键字封锁的是this对象本身,而在静态方法中加入sychronized关键字封锁的就是类本身。
静态方法是所有类实例对象所共享的,因此线程对象在访问此静态方法时是互斥访问的,从而可以实现线程的同步,代码如下所示:

代码
package com.thread.test;

class MyThread implements java.lang.Runnable
{
    private int threadId;
   
    public MyThread(int id)
    {
        this.threadId = id;
    }
    @Override
    public void run()
    {
        taskHandler(this.threadId);
    }
    private static synchronized void taskHandler(int threadId)
    {
        for (int i = 0; i < 100; ++i)
        {
            System.out.println("Thread ID: " + threadId + " : " + i);
        }
    }
}
public class ThreadDemo
{
/**
* @param args
* @throws InterruptedException
*/
    public static void main(String[] args) throws InterruptedException
    {
        for (int i = 0; i < 10; ++i)
        {
            new Thread(new MyThread(i)).start();
            Thread.sleep(1);
        }
    }
}

delphi递归函数应用 代码实例,主要是介绍基本递归的实现,函数的调用等。 立即下载

相关推荐

VB6 在笛卡尔坐标系中用PlgBlt函数以坐标点为顶点贴平行四边形图片

VB6 在笛卡尔坐标系中用PlgBlt函数以坐标点为顶点贴平行四边形图片

Frida框架-端口转发错误“Unable to start: Error binding to address 127.0.0.1:27042: Address already in use”

有些时候,你的系统中只能运行一个实例。 frida中使用adb forward进行端口转发。 1. 相关命令: (1)转发, adb forward tcp:27042 tcp:27042 adb forward tcp:27043 tcp:27043

记录和分享程序人生的点点滴滴 2万+

三级树形菜单列表,附带完整工程解说,SQL建表语句和分析,立马看懂和运用

本工程连接数据库生成树形菜单,在开发中可做出权限菜单生成,列表菜单生成。第二级和第三级节点自由增加。附带完整SQL建表和插入数据语句,结构分析。代码重要关键部分注释和打印。附带完整测试语句,解说。方便大家理解和熟悉。

Unable to start: Error binding to address 127.0.0.1:27042: Address already in use

杀掉进程,Android 查看进程是 pa -e 不是 ps aux ps -e | grep frida kill -9 pid

qq_41236493的博客 7756

网管必备手册

最好使用的一本手册 网管必备手册

手把手教你逆向京东搜索接口:H5ST 556位参数生成与V8补环境技巧

本文深入解析了京东搜索接口中关键的H5ST 556位参数生成机制,并提供了详细的逆向实战指南。针对其复杂的反爬虫环境检测,文章重点介绍了通过链式补环境技巧,在Node.js中完整模拟浏览器环境(包括原型链检测和指纹验证)的方法,帮助开发者成功绕过防护并生成有效参数。

weixin_29315091的博客 482

Frida 重启失败问题(Unable to start: Could not listen on address 127.0.0.1, port 27042: Error binding to a)

Unable to start: Could not listen on address 127.0.0.1, port 27042: Error binding to address 127.0.0.1:27042: Address already in use

qq_42229759的博客 7963

CV领域交叉注意力机制:QKV在图像特征增强中的核心作用解析

本文深入解析了CV领域中交叉注意力机制的核心组件QKV在图像特征增强中的关键作用。通过通俗类比和实战案例,阐述了Q(查询)、K(键)、V(值)如何协同实现动态权重分配,从而在目标检测、图像分割与生成等任务中显著提升模型性能与语义对齐能力。

weixin_29194817的博客 438

Frida 使用教程和错误汇总

Frida 使用教程和错误汇总 Frida安装 Frida基本使用教程 python接口错误汇总1. 端口转发 Frida安装 Frida基本使用教程 Frida进阶使用教程 Frida python接口 错误汇总 1. 端口转发

m0_54352040的博客 3万+

VMware vSphere运维管理手册

ESXi 7.0 引入了一种系统存储布局,可对大型模块和第三方组件进行灵活的分区管理和支持,同时简化了调试操作。ESXi 7.0 系统存储更改在 ESXi 7.0 之前,分区大小固定不变,除 /scratch 分区和可选 VMFS 数据存储之外,且分区号是静态的,这些限制了分区管理。在 ESXi 7.0 中,分区整合为更少且更大的可扩展分区,具体取决于所使用的引导介质及其容量。ESXi 7.0 系统存储布局包含四个分区:分区适用情况类型系统引导存储引导加载程序和 EFI 模块。FAT16。

Avenjan优快云博客 3624

AI应用架构师:引领半导体良率AI预测的变革浪潮

在半导体行业这个技术密集、资本密集且竞争异常激烈的领域,良率是决定企业盈利能力的关键指标。每提升1%的良率可能意味着数亿美元的利润增长。然而,随着制程节点不断缩小至3nm、2nm甚至更先进水平,传统的良率管理方法已难以应对日益复杂的制造流程和指数级增长的数据量。本文将深入探讨AI应用架构师如何成为这场变革的核心驱动力,通过设计和实施先进的AI预测系统,将半导体良率预测从传统的"事后分析"转变为"事前预测"和"实时优化"。

AI大模型应用之禅 403

Workerman--unable to connect to tcp://0.0.0.0:7272 (Address already in use)

7th,Jan,2016 unable to connect to tcp://0.0.0.0:7272 (Address already in use) 当我再一次的使用php start.php start开启时,出错了: lsof -i:7272查看端口被什么进程占用: 解决方式: 杀死这些进程, 应该就可以了。 分析: 初步判断是系

Jolie_Yang的博客 9538

如何用AP525 测试输入信号的相位,频响,延时,Pop和卡顿

假设信号不是从AP输出,是功放或者其他的播放设备输出的信号,接入到AP525的输入端。

帮助100万人颠覆负面潜意识,实现人生蜕变,培养1万名潜意识开发导师 2402

Java中的线程同步详解

Java中的线程同步详解大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在多线程编程中,线程同步是一个非常重要的话题。线程同步的目的是为了保证多个线程访问共享资源时,能够避免数据的不一致性和竞争条件。Java 提供了多种机制来实现线程同步,包括 synchronized 关键字、显式锁 (Re...

weixin_41239550的博客 155

基于YOLOv11的工业装配完整性智能检测系统

在现代工业生产中,产品质量控制是确保企业竞争力的关键环节。其中,装配完整性检查——即检测产品是否安装了所有应有的部件,是质量检测中的重要一环。传统的人工检测方法存在效率低、易疲劳、主观性强等问题。本文提出了一种基于深度学习的目标检测算法YOLOv11的工业装配完整性智能检测系统,通过计算机视觉技术自动识别和验证产品装配的完整性。本文将详细阐述从数据准备、模型训练到系统部署的完整流程,提供可执行的代码实现,并介绍一个适用于该任务的参考数据集。

YOLO 552

AD-Copilot 论文解读:把“大模型看图”升级为“对照检验”的工业异常检测助手

本文提出AD-Copilot,一个面向工业异常检测的视觉语言助手,通过视觉上下文比较解决现有方法的不足。针对工业场景中多模态大模型表现不佳的问题,作者指出核心原因在于缺乏工业数据和比较能力不足。为此,论文提出三个关键贡献:构建Chat-AD数据集,设计Comparison Encoder显式建模图像差异,以及采用多阶段训练策略。实验表明,该方法在MMAD基准上达到82.29%准确率,定位任务提升3.35倍,并展现出良好的泛化能力。消融实验验证了比较模块的有效性,表明其成功源于高质量比较数据与显式比较模块的协

blanokvaffy的博客 332

Java面试题:什么是Java中的线程同步?

在多线程编程中,线程同步是一个非常重要的概念。Java作为一种广泛使用的编程语言,提供了多种机制来实现线程同步。本文将详细介绍Java中的线程同步。

qq_58299462的博客 733

【高级】系统架构师 | 2026年上半年案例分析真题

标准答案:系统因缺乏足够历史数据(用户行为、物品信息或评分等),难以做出准确推荐的问题。另外两种:物品冷启动(新课程 / 新知识点缺少互动数据)系统冷启动(平台上线初期整体数据稀缺)类型典型表现常见缓解用户冷启动新注册学员无历史问卷/前测、热门兜底、人口统计学特征、知识图谱前置测评物品冷启动新课无人学无人评内容特征推荐、专家标注、探索流量系统冷启动新平台双边都稀缺规则引擎、运营冷启、知识图谱强约束路径本题已点明「用户冷启动」,另外两种按推荐系统经典三分法作答即可。

大胆尝试,小心实践 358

Java 中的线程同步方案

Java 中的线程同步方案|线程安全的实现方法 同步是指在多个线程并发访问共享数据时保证共享数据在同一时刻只被一条线程使用。 1. 互斥同步即阻塞同步 临界区、互斥量、信号量都是常见的互斥实现方式。 在 Java 中,最基本的同步方式就是 synchronized 关键字 被 synchronized 修饰的同步块对同一条线程来说是可重入的。这意味着同一线程反复进入同步块也不会出现自己把自己锁死的情况 被 synchronized 修饰的同步块在持有锁的线程执行完毕并释放锁之前,会无条件的阻塞后面其他

kang2411212的博客 647

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

java 多线程同步_详解Java多线程编程中的线程同步方法

1、多线程的同步:1.1、同步机制:在多线程中,可能有多个线程试图访问一个有限的资源,必须预防这种情况的发生。所以引入了同步机制:在线程使用一个资源时为其加锁,这样其他的线程便不能访问那个资源了,直到解锁后才可以访问。1.2、共享成员变量的例子:成员变量与局部变量:成员变量:如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作,这多个线程是共享一个成员变量的。局部变量:如果一个变量是...

weixin_42515100的博客 334

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

谈谈Java线程中的同步

1、对象与锁 每一个Object类及其子类的实例都拥有一个锁。其中,标量类型int,float等不是对象类型,但是标量类型可以通过其包装类来作为锁。单独的成员变量是不能被标明为同步的。锁只能用在使用了这些变量的方法上。成员变量可以被声明为volatile,这种方式会影响该变量的原子性,可见性以及排序性。 类似的,持有标量变量元素的数组对象拥有锁,但是其中的标量元素却不拥有锁。(也就是说,没

月吖吖 244

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

上一篇: java中的线程创建和使用
下一篇: java中的定时器
liranke
博客等级 码龄20年 4939粉丝 594原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liranke

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值