Java多线程并发编程 并发三大要素

发布时间 - 2026-01-11 01:14:27    点击率:

一、原子性

原子,一个不可再被分割的颗粒。原子性,指的是一个或多个不能再被分割的操作。

int i = 1; // 原子操作
i++; // 非原子操作,从主内存读取 i 到线程工作内存,进行 +1,再把 i 写到朱内存。

虽然读取和写入都是原子操作,但合起来就不属于原子操作,我们又叫这种为“复合操作”。

我们可以用synchronized 或 Lock 来把这个复合操作“变成”原子操作。

例子:

 private synchronized void increase(){
    i++;
  }

 private int i = 0;
  Lock mLock = new ReentrantLock();

  private void increase() {
    mLock.lock();
    try {
      i++;
    } finally{
      mLock.unlock();
    }
  }

这样我们就可以把这个一个方法看做一个整体,一个不可分割的整体。

除此之前,我们还可以用java.util.concurrent.atomic里的原子变量类,可以确保所有对计数器状态访问的操作都是原子的。

例子:

AtomicInteger mAtomicInteger = new AtomicInteger(0);
 
  private void increase(){
    mAtomicInteger.incrementAndGet();
  }

二、可见性

当多线程访问某一个(同一个)变量时,其中一条线程对此变量作出修改,其他线程可以立刻读取到最新修改后的变量。

int i = 0;
// 线程 1 执行
i++;

// 线程 2 执行
System.out.print("i=" + i);

即使是在执行完线程里的 i++ 后再执行线程 2,线程 2 的输入结果也会有 2 个种情况,一个是 0 和 1。

因为 i++ 在线程 1(CPU1)中做完了运算,并没有立刻更新到主内存当中,而线程 2(CPU2)就去主内存当中读取并打印,此时打印的就是 0。

synchronized和Lock能够保证可见性。

另外volatile关键字也可以解决这个问题(下一篇会讲到)。

三、有序性

我们都知道处理器为了拥有更好的运算效率,会自动优化、排序执行我们写的代码,但会确保执行结果不变。

例子:

int a = 0; // 语句 1
int b = 0; // 语句 2
i++; // 语句 3
b++; // 语句 4

这一段代码的执行顺序很有可能不是按上面的 1、2、3、4 来依次执行,因为 1 和 2 没有数据依赖,3 和 4 没有数据依赖, 2、1、4、3 这样来执行可以吗?完全没问题,处理器会自动帮我们排序。

在单线程看来并没有什么问题,但在多线程则很容易出现问题。

再来个例子:

// 线程 1
init();
inited = true;

// 线程 2
while(inited){
	work();
}

init(); 与 inited = true; 并没有数据的依赖,在单线程看来,如果把两句的代码调换好像也不会出现问题。

但此时处于一个多线程的环境,而处理器真的把这两句代码重新排序,那问题就出现了,若线程 1 先执行 inited = true; 此时,init() 并没有执行,线程 2 就已经开始调用 work() 方法,此时很可能造成一些奔溃或其他 BUG 的出现。

synchronized和Lock能确保原子性,能让多线程执行代码的时候依次按顺序执行,自然就具有有序性。

而volatile关键字也可以解决这个问题,volatile 关键字可以保证有序性,让处理器不会把这行代码进行优化排序。


# Java多线程  # 并发编程  # Java并发编程示例(一):线程的创建和执行  # Java并发编程示例(六):等待线程执行终止  # Java并发编程之显示锁ReentrantLock和ReadWriteLock读写锁  # Java并发编程之栅栏(CyclicBarrier)实例介绍  # Java并发编程示例(二):获取和设置线程信息  # Java并发编程示例(七):守护线程的创建和运行  # Java并发编程示例(十):线程组  # Java并发编程总结——慎用CAS详解  # 理解Java多线程之并发编程  # 多线程  # 都是  # 可以用  # 两句  # 解决这个问题  # 单线程  # 是在  # 见性  # 会有  # 多个  # 就不  # 但在  # 很容易  # 能让  # 再来  # 很可能  # 或其他  # 就去  # 已经开始  # 写到 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: javascript中数组(Array)对象和字符串(String)对象的常用方法总结  Laravel如何处理JSON字段_Eloquent原生JSON字段类型操作教程  如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?  Laravel用户密码怎么加密_Laravel Hash门面使用教程  手机钓鱼网站怎么制作视频,怎样拦截钓鱼网站。怎么办?  Laravel如何发送系统通知_Laravel Notifications实现多渠道消息通知  如何在景安服务器上快速搭建个人网站?  太平洋网站制作公司,网络用语太平洋是什么意思?  网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?  学生网站制作软件,一个12岁的学生写小说,应该去什么样的网站?  移动端手机网站制作软件,掌上时代,移动端网站的谷歌SEO该如何做?  阿里云高弹*务器配置方案|支持分布式架构与多节点部署  Laravel如何创建自定义Artisan命令?(代码示例)  Laravel如何理解并使用服务容器(Service Container)_Laravel依赖注入与容器绑定说明  Laravel怎么进行数据库事务处理_Laravel DB Facade事务操作确保数据一致性  Android okhttputils现在进度显示实例代码  Laravel如何处理跨站请求伪造(CSRF)保护_Laravel表单安全机制与令牌校验  js代码实现下拉菜单【推荐】  Laravel如何记录自定义日志?(Log频道配置)  简单实现jsp分页  Laravel如何使用Telescope进行调试?(安装和使用教程)  php静态变量怎么调试_php静态变量作用域调试技巧【解答】  标题:Vue + Vuex 项目中正确使用 JWT 进行身份认证的实践指南  Python数据仓库与ETL构建实战_Airflow调度流程详解  PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)  javascript和jQuery中的AJAX技术详解【包含AJAX各种跨域技术】  电视网站制作tvbox接口,云海电视怎样自定义添加电视源?  Laravel如何创建自定义Facades?(详细步骤)  Win11怎么开启自动HDR画质_Windows11显示设置HDR选项  如何在云主机上快速搭建多站点网站?  Laravel怎么实现搜索高亮功能_Laravel结合Scout与Algolia全文检索【实战】  JavaScript常见的五种数组去重的方式  Laravel如何实现本地化和多语言支持_Laravel多语言配置与翻译文件管理  网站建设保证美观性,需要考虑的几点问题!  如何快速查询域名建站关键信息?  网站制作公司哪里好做,成都网站制作公司哪家做得比较好,更正规?  Laravel模型关联查询教程_Laravel Eloquent一对多关联写法  EditPlus 正则表达式 实战(3)  如何用AI帮你把自己的生活经历写成一个有趣的故事?  如何用低价快速搭建高质量网站?  教学论文网站制作软件有哪些,写论文用什么软件 ?  如何选择可靠的免备案建站服务器?  Laravel如何与Inertia.js和Vue/React构建现代单页应用  如何用VPS主机快速搭建个人网站?  Windows家庭版如何开启组策略(gpedit.msc)?(安装方法)  Laravel怎么集成Log日志记录_Laravel单文件与每日日志配置及自定义通道【详解】  Laravel storage目录权限问题_Laravel文件写入权限设置  如何快速查询网址的建站时间与历史轨迹?  Laravel集合Collection怎么用_Laravel集合常用函数详解  Laravel如何使用Blade组件和插槽?(Component代码示例)