带你读懂《Java并发编程》:第3章 助于线程安全的三剑客:final & volatile & 线程封闭...

本地AI代码助手:智能解析大型代码库,实现自动化重构与理解 在软件开发中,大型代码库的理解与维护是常见挑战。传统方法依赖人工阅读和有限上下文工具,效率低下。通过结合检索增强生成(RAG)和多智能体(Multi-Agent)架构,现代AI工具能够智能解析代码结构,理解模块关系,并精准定位相关代码片段。这种技术不仅能提升代码探索效率,还能自动化执行重构、文档生成等任务,在遗留系统维护、快速上手新项目等场景中发挥关键作用。本文以blackboxaicode/cli为例,展示了如何利用其代码感知和Workflow Automation能力,高效处理复杂代码库。 阅读详情

点击上方蓝字关注我们

我们简要的回顾前文:

《第1章 多线程安全性与风险》介绍了并发编程,在维护难度、性能以及活跃性三个方面,所带来的风险与优势;

《第2章 影响线程安全性的原子性和加锁机制》介绍了并发编程核心概念 -- 线程安全性,介绍了用同步的手段,来避免多个线程在同一时刻访问相同的数据;

今天分享的是《Java并发编程实战》第3章 -- “对象的共享”:介绍用安全共享和发布对象的手段,来让多个线程能够安全的同事访问同一数据。

开始前,我们先回顾下几个重要的基础知识:缓存一致性 和 Java内存模型。

现实计算机系统是存在缓存一致性问题的,见下图:

  • 现实因素:由于计算机存储设备与处理器的运算速度有个数量级的差距(即便存储设备使用SSD,还是比处理器慢几个数量级),所以计算机系统不得不增加一层读写速度尽可能接近处理器速度的高速缓存Cache来作为内存和处理器之间的缓冲。

  • 缓存一致性(Cache Coherence):基于高速缓存的存储交互解决了处理器和内存的速度矛盾,但是引入了缓存一致性(在多处理器系统中,每个处理器都有自己的高速缓存,而它们又共享同一个主内存(Main Memory),当多个处理器的运算任务都涉及同一块主内存区域时,将可能导致各自的缓存数据不一致)。

  • Java内存模型(Java Memory Model,JMM):基于现实因素制约造成的内存并发不一致,JVM 定义了一套 JMM 来屏蔽掉各种硬件和操作系统的内存访问差异,以达到统一共和,哦不,是让 Java 程序一处编译到处运行,实现在各种平台下都能达到一致的内存访问效果。

    1)JMM:规定所有变量都存在主内存(Main Memory)了,每条线程还有自己的工作内存(Working Memory),工作内存保存了变量的主内存拷贝。

2)JMM 内存模型里,从Java线程 -> 工作内存 -> 主内存之间的1次读写分为8个基本操作:(篇幅所限不展开,后续文章会跟进讲解)

操作作用
lock (锁定)作用于主内存的变量,把一个变量标识为线程独占状态
unlock (解锁)

作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定

read (读取)作用于主内存变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用
load (载入)

作用于工作内存的变量,它把read操作从主存中变量放入工作内存中

use (使用)作用于工作内存中的变量,它把工作内存中的变量传输给执行引擎,每当虚拟机遇到一个需要使用到变量的值,就会使用到这个指令
assign (赋值)作用于工作内存中的变量,它把一个从执行引擎中接受到的值放入工作内存的变量副本中
store (存储)作用于主内存中的变量,它把一个从工作内存中一个变量的值传送到主内存中,以便后续的write使用
write (写入)作用于主内存中的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中

3)JMM的内存间交互操作时序见下图:

对象的可见性

我们通过下面的例子来认识下潜在的变量可见性问题。

例子1:变量的可见性不暴露于多线程

/**
* <p>可见性测试</p>
 */
public class NoVisibility {
//非线程安全的状态变量
private static boolean ready;
private static int number;


private static class ReaderThread extends Thread{
@Override
public void run() {
while (!ready)
//挂起,让出CPU占用权
        Thread.yield();
      System.out.println("ready = " + ready + " , and number = " + number);
    }
  }


public static void main(String[] args) throws InterruptedException {
new ReaderThread().start();
    number=43;
    ready=true;
  }
}


例子1 输出结果:大部分情况下,我们运行程序可以得到下面的输出:

ready = true , and number = 43

例子1 代码解析:

主线程A开启了一个异步线程B(B负责循环校验 ready变量,如果为false,继续让出CPU所有权空轮转,如果为true,打印日志)。这个程序的大部分情况运行结果都正确,但它并非线程安全。

  • 上面的 NoVisibility 类可能会无限循环下去,因为 ready 值可能对Reader线程来说一直是不可见的。

  • 在更为特殊的情况下,NoVisibility甚至可能会打印出0,因为可能会在写入number之前写入ready值,这是由于著名的“指令重排序”(reordering)现象。

Q1:指令重排序是什么?

指令是指示计算机执行某种操作的命令,如:数据传送指令、算术运算指令、位运算指令、程序流程控制指令、串操作指令、处理器控制指令。

Java语言规范JVM线程内部维持顺序化语义:

只要程序的最终结果与它顺序化情况的结果相等,那么指令的执行顺序可以与代码逻辑顺序不一致,这个过程就叫做指令的重排序。    

指令重排序的意义:使指令更加符合CPU的执行特性,最大限度的发挥机器的性能,提高程序的执行效率。

代码优化:只要数据在多个线程之间共享,就使用正确的同步。

维护可见性的两种手段

维护可见性也有两种手段:一是同步锁,二是使用volatile关键字。

维护可见性之一:同步锁使用。

例子1 的NoVisiability 展示了缺乏同步的程序可能产生的错误情况:失效数据。失效数据可能不会同时出现,一个线程可能获取新值,而另一个获取旧值。我们看下例子2和例子3:

反例2:线程不安全的例子

@NotThreadSafe
public class MutablInteger {
private int value;


public int getValue() {
return this.value;
  }


public void setValue(final int value) {
this.value = value;
  }
}

正例3:使用同步锁优化后的例子

@ThreadSafe
public class SynchronizedInteger {
private int value;


public synchronized int getValue() {
return this.value;
  }


public synchronized void setValue(final int value) {
this.value = value;
  }
}

例子2、3的代码解析:

  • 我们通过对getter/setter方法同时加锁,确保所有线程都在拥有同步的情况下访问value。

加锁的含义不仅仅局限于互斥行为,还包括内存可见性。为了确保所有线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步。

维护可见性之二:volatile 变量。

例子2和例子3,其实在没有同步的情况下,可能会得到一个失效值,但至少是由之前的线程设置的,不是随机值,此称为“最低安全性”(out-of-thin-airsafety)。可是,最低安全性适用于绝大多数变量,但不适用于非volatile类型的64位数值变量。因此我们需要使用 volatile 来声明它们或者用锁保护起来。

JMM 要求,变量的读取操作和写入操作都必须是原子操作,但对于非volatile类型的long和double变量,JVM允许将64位的读操作或写操作分解为两个32位的操作。 

当读取一个非volatile类型的long变量时,如果对该变量的读操作和写操作在不同的线程中执行,那么很可能会读取到某个值的高32位和另一个值的低32位。

Volatile变量

Java语言提供了一种稍弱的同步机制,即volatile变量,用来确保变量的更新操作通知到其他线程。

  • 禁止重排序:当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。

  • 读取写入作用于主内存:volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。

例子4:volatile 的使用

public class CountSheeps {
  static volatile boolean asleep;
  public static void main(String[] args) throws InterruptedException {
    new CountSheepsThread().start();
    Thread.sleep(10000);
    asleep = true;
  }
  private static class CountSheepsThread extends Thread{
    @Override
    public void run() {
      while (!asleep)
        Thread.yield();
      countSheep();
    }
    private void countSheep() {
      System.out.println("zzz...");
    }
  }
}

例子4分析:

在例子4中,主线程A在休眠10s后,将 asleep 变量的值修改为true,在A休眠的10s里,线程B一直处于轮训中的可执行状态,直到asleep的值被修改。换句话说,asleep 是线程A和B的共享变量,利用volatile修饰之后,A线程的改动会及时通知B线程,进而B线程执行后续业务。

给volatile做个总结:

加锁机制既可以确保可见性又可以确保原子性,而volatile变量只能确保可见性。

《Java并发编程》建议当且仅当满足以下所有条件时(相当苛刻的条件),才应该使用volatile变量:

  • 变量的写入操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。

  • 该变量不会与其他状态变量一起纳入不变性条件中。 

  • 在访问变量时不需要加锁。

对象的发布/逸出

对象的“发布(Publish)”是指:一个对象能够在当前作用域之外的代码中使用。对象的“逸出(Escape)”是指:当某个不应该发布的对象被发布时,这种情况就被称为。常见的发布对象的手段有两种:

  • 第一种发布对象方式是:将对象那个的引用保存到一个公有的静态变量中,以便任何类和线程都能看见该对象。

例子5:不安全的对象发布

@NotThreadSafe
public class PublishObject2 {
  private String[] states = new String[] {"AK","AL"};
  public String[] getStates() { return states; }
}

例子5 解析:

由于states逸出了它所在的作用域,因为这个本应是私有的变量已经被发布了,导致任何调用者都可以修改这个数组的内容。
 

  • 第一种发布对象方式是:发布一个内部的类实例。

例子6:也是不安全的对象发布。

/**
 * <p>内部类,this在构造函数中逸出</p>
 */
@NotThreadSafe
public class ThisEscape {
  public static void main(String[] args) {
    EventSource eventSource = new EventSource();
    new ThisEscape(eventSource);
  }
  // ThisEscape 对象的构造器
  public ThisEscape(EventSource source) {
    source.registerListener(
        new EventListener() {
          //发布匿名对象(也发布了ThisEscape实例)
          public void onEvent(Event e) {
            doSomething(e);
          }
        },this);
  }
  private void doSomething(Event e) {
  }
}
public class EventSource {
  public void registerListener(EventListener eventListener, ThisEscape name) {
    System.out.println("EventSource知道了这个类,也会将它告诉 EventListener");
    eventListener.esclape(name);
  }
}
public class EventListener {
  public void onEvent(Event e) {
  }
  public void esclape(ThisEscape name) {
    System.out.println("这是不安全的对象发布,因为EventSource的告知, EventListener 也知道 ThisEscape 被构建了:" + name.getClass());
  }
}

例子6 输出结果:

EventSource知道了这个类,也会将它告诉 EventListener
这是不安全的对象发布(可以在一个对象的构造器里做点别的事情,该对象未完全构造完成,就可以被别的地方调用,因此属于逸出现象),
因为EventSource的告知, EventListener 也知道 ThisEscape 被构建了:class shizhanthread.chapter3.ThisEscape

例子6 解析:

由于在构造器中进行内部类的创建,导致该构造器的对象同样被“无意中发布了”。

隐式或者显示的使用this引用,会导致构造器拥有者逸出,因此,不要在构造过程中使this引用。

线程封闭

上面提到的对象发布和逸出,是为了合理处理对象作用域的范围,说到底是为了不让它被其它线程随意修改数据和状态。那有没有断绝其他线程干扰的方法呢?

有的,避免使用同步的方式就是不共享数据,即:线程封闭(Thread Confinement)。

线程封闭(Thread Confinement)技术:只在单线程内访问数据,不需要同步,它是实现线程安全性的最简单方式之一。

线程封闭的实现手段有三种:Ad-hoc线程封闭、栈封闭 和 ThreadLocal 类。

Ad-hoc 线程封闭

Ad-hoc线程封闭,用一句大白话说:维护线程封闭性的职责完全由程序实现来承担(你的线程封闭业务逻辑,如果你用Java来写,就用Java的语法来维护,并且逻辑和真实运行结果都要由你自个保证)。

也就是说,这是完全靠实现者控制的线程封闭,因此,也导致Ad-hoc线程封闭非常脆弱,没有任何一种语言特性能将对象封闭到目标线程上。

维基百科上对于Ad hoc这个词有专门的解释“Ad hoc是拉丁文常用短语中的一个短语。这个短语的意思是'特设的、特定目的的、即席的、临时的、将就的、专案的'。

这个短语通常用来形容一些特殊的、不能用于其它方面的的,为一个特定的问题、任务而专门设定的解决方案。这个词汇须与a priori区分。

栈封闭

栈封闭,用一句大白话说,就是局部变量。

多个线程访问一个方法,此方法中的局部变量都会被拷贝一分儿到线程栈中。所以局部变量是不被多个线程所共享的,也就不会出现并发问题(有疑惑的同学,可以回顾开篇提及的 Java内存模型)。所以能用局部变量就别用全局的变量,全局变量容易引起并发问题。

ThreadLocal类

ThreadLocal,用一句大白话说,它是实现线程封闭的最好方法。ThreadLocal内部维护了一个Map,Map的key是每个线程的名称,而Map的值就是我们要封闭的对象。每个线程中的对象都对应着Map中一个值,也就是ThreadLocal利用Map实现了对象的线程封闭。(篇幅所限,后续源码分析再做展开)

ThreadLocal 类提供了get与set等访问接口或方法,这些方法为每个使用该变量的线程都存有一份独立的副本,因此get总是返回由当前执行线程在调用set时设置的最新值。

对象不变性和Final域

对象的不可变性(Immutable Object)是通过 Final域声明,来实现不可变性对象的构造。而被 Final 关键字修饰类型的域是不能修改的,Final 实际上可以用于修饰类/方法/数据域:

  • 类:Final 类不可被继承,无子类,保证用户调用时动作的一致性,可以防止子类覆盖情况的发生。

  • 方法:方法不可被覆盖,private 修饰的方法默认带上了final。

  • 数据域:变量的值为常量,常量的地址不可改变,但在地址指向的内存空间保存的值(即对象的属性)是可以改变的。【本章讲的主要是数据域这个情况】

例子7:在不可变对象中可以使用可变对象管理他们的状态

@Immutable
public final class ThreeStooges {
  //不可变对象的引用,但是Set的数据可以被更新
  private final Set<String> stooges = new HashSet<String>();
  public ThreeStooges() {
    stooges.add("Moe");
    stooges.add("Larry");
    stooges.add("Curly");
  }
  //这是读操作,允许并发读(除非还有并发写的操作,否则就是不安全的)
  public boolean isStooge(String name) {
    return stooges.contains(name);
  }
}

例子7:代码分析

尽管stooges 是保管姓名的Set对象,它是可变的。但从设计来看,在Set对象构造完成后,没有对外暴露任何修改的API,所有的对象状态都通过一个final 域来访问,因此实现了对象不变性。

不可变对象一定是线程安全的。

总结

我们在实战领域编写并发程序,在使用或者共享对象时,《Java并发实战》给我们总结了4条规则:

  • 线程封闭

  • 只读共享。共享的只读对象可以由多个线程并发访问,但任何线程都不能修改它。共享的只读对象包括不可变对象和事实不可变对象

  • 线程安全共享。线程安全地对象在器内部实现同步。

  • 保护对象。被保护的对象只能通过持有特定的锁来方访问。

推荐阅读

《源码系列》

JDK之Object 类

JDK之BigDecimal 类

JDK之String 类

《经典书籍》

Java并发编程实战:第1章 多线程安全性与风险

Java并发编程实战》:第2章 影响线程安全性的原子性和加锁机制

Effective Java 第53条:接口优先于反射机制

Effective Java 第52条:通过接口引用对象

Effective Java 第54条:谨慎的使用本地方法

《服务端技术栈》

Docker 核心设计理念

Kafka史上最强原理总结

HTTP的前世今生

《算法系列》

读懂排序算法(二):希尔排序算法

读懂排序算法(三):堆排序算法

读懂排序算法(四):归并算法

读懂排序算法(五):快速排序算法

扫描二维码

获取技术干货

后台技术汇

点个“在看”表示朕

已阅

李航《统计学习方法》课后习题答案(第2版) 李航《统计学习方法》课后习题答案(第2版) 章节 链接 第1章 统计学习及监督学习概论 点击进入 第2章 感知机 点击进入 第3章 k近邻法 点击进入 第4章 朴素贝叶斯法 点击进入 第5章 决策树 点击进入 第6章 逻辑斯谛回归与最大熵 点击进入 第7章 支持向量机 点击进入 第8章 提升方法 点击进入 第9章 EM算法及其推广 点击进入 第10章 隐马尔可夫模型 点击进入 第11章 条件随机场 点击进入     也可进入我的个人主页查看分类专栏 阅读详情

相关推荐

STM32实战——七段数码管动态扫描技术详解

本文详细解析了STM32控制七段数码管的动态扫描技术,包括硬件连接、CubeMX配置及编程实现。通过分时复用原理和优化代码逻辑,实现稳定显示效果,并解决亮度不均、闪烁等常见问题。适合嵌入式开发者快速掌握STM32数码管驱动技术。

weixin_42561143的博客 279

java并发编程读书笔记(1)-- 对象的共享

1. 一些原则 RIM(Remote Method Invocation):远程方法调用 Race Condition:竞态条件 Servlet要满足多个线程的调用,必须是线程安全的 远程对象,即通过远程方法调用将对象放入字节流中传给其他jvm的对象,要特别注意对象中的共享状态 Shared:共享的 Mutable:可变的 当设计线程安全的类时,良好的...

weixin_33817333的博客 187

用Arduino和FS-i6X遥控器,从零开始打造你的第一只仿生扑翼蝴蝶(附完整代码解析)

本文详细介绍了如何利用Arduino和FS-i6X遥控器从零开始制作仿生扑翼蝴蝶,包括硬件准备、电路连接、代码解析和调试技巧。通过完整的代码示例和参数说明,帮助读者快速掌握仿生机器人的制作要点,实现蝴蝶的自然飞行效果。

weixin_28727975的博客 310

Java杂谈5——关键字final与volatile

Final关键字   在Java语言中,随着语境的不同final关键字所代表的语义会有一些细微的差异。总的来说,final关键字表达的含义是“禁止修改”,这层有点类似于C++中的const关键字。之所以要采用final关键字,一般是会出于性能和设计层面的考虑。下文会具体讨论final关键字在不同语境中的具体用法。 Final + 属性   用final关键字修饰的属性,对于Java编译器来说...

weixin_30955617的博客 406

Python+AI能源管理实战:从电力负荷预测到智能调度的全流程开发

本系统展示了Python在能源管理领域的强大能力,通过AI技术实现了从预测到优化的智能决策闭环。随着碳中和目标的推进,智能能源系统将成为新型电力系统的核心大脑。📌 专业建议:系统部署需考虑网络安全防护,关键控制指令应设置多重验证机制!关注我的优快云账号获取能源系统安全最佳实践~下期预告:我们将探索Python在智慧医疗中的应用,开发基于多模态数据的智能诊断辅助系统。想提前获取代码?评论区留言"智慧医疗"获取GitHub源码链接!

资深全栈架构师,乐于在 优快云 分享技术见解,与大家携手共进,共攀技术巅峰! 625

AI人工智能全模态大模型架构:推动智能交通发展的架构设计

本文旨在阐述全模态大模型在智能交通领域的架构设计原理和应用方法。我们将探讨如何利用多模态AI技术解决交通流量预测、事故预警、路线优化等关键问题。文章将从基础概念入手,逐步深入技术细节,最后探讨实际应用和未来发展方向。全模态大模型:能够处理和理解多种数据模态(如图像、文本、语音等)的大型AI模型智能交通系统(ITS):利用先进技术优化交通流量和安全性的综合系统多模态融合:将不同数据源的信息整合处理的技术核心概念回顾全模态大模型是能够处理多种数据类型的强大AI系统。

AGI×大数据,开启智能时代的认知跃迁;解码AGI,赋能数据驱动的智能革命。 835

并发编程(二十五) - volatile与final原理

并发编程(二十五) - volatile与final原理

及时当勉励,岁月不待人 2064

自适应动态规划硕士博士论文学习

强化学习关注随机过程中的序贯决策问题,而自适应动态规划关注动态系统的控制问题。吸引域:系统渐近稳定的区域。

DarlingLSA的博客 1425

Java面试补给站——final、volatile、synchronized三大关键字

如果说语法是一个编程语言的骨架,那么关键字就是骨架的关节。 在Java中有各种功能的关键字,最常用的int,break,public这些关键字都是在编程过程中必不可少的。 本文从面试提问的角度聊一下final、volatile、synchronized这三个关键字。 1.开篇 为什么就聊final、volatile、synchronized这三个关键字呢?并不是说其他关键字不重要,而是在笔...

yan245294305的博客 1579

主流反爬虫、反作弊防护与风控对抗手段

主流反爬虫、反作弊风控防护中的核心设计点与对抗策略

吴秋霖的博客 2555

YOLOv11涨点改进 | 全网独家创新,注意力改进篇 | TGRS 2025 | 引入APCM自适应像素级协同机制,动态增强目标区域、抑制背景噪声,助力YOLOv11做红外小目标检测有效涨点

本文提出了一种基于APCM模块改进的YOLOv11网络模型,通过像素级局部-全局协同建模增强目标特征并抑制背景噪声。APCM模块采用轻量化设计,无需复杂参数,能有效提升小目标检测性能。文章详细介绍了APCM的原理、优势及其在红外小目标检测中的应用,包括模块结构、核心代码实现和YAML配置文件修改方法。实验结果表明,该方法在NUAA-SIRST和IRSTD-1K数据集上优于现有技术,显著提高了复杂场景下的检测精度与鲁棒性。

Ai缝合怪、助力小伙伴高效发论文 118

深入理解java内存模型04-volatile,锁,final

深入理解java内存模型 -学习笔记 深入理解java虚拟机 JSR133 转载自并发编程网 本文链接地址: 深入理解Java内存模型 VALATILE valatile的特性 关键字valatile可以说是Java虚拟机提供的最轻量级的同步机制,当一个变量被定义为volatile类型之后,它将具备两种特性: 可见性:另一种说法是:对于volatile变量...

dark 311

AI 模型优化与部署秘籍:从理论到实战

本文系统介绍了AI模型优化与部署的关键技术。模型剪枝通过去除冗余参数减小模型规模,量化技术降低计算精度以提升效率,蒸馏方法实现知识从大模型到小模型的迁移。TensorRT通过层融合和精度校准加速GPU推理,ONNX格式实现跨框架模型转换,TFLite则优化移动端部署。这些技术共同解决了AI模型在资源受限环境下的部署难题,显著提升了模型运行效率,为AI应用落地提供了重要支撑。

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 247

带你读懂《Java并发编程》:第3章 助于线程安全的三剑客:final&valitale&线程封闭...

点击上方蓝字关注我们我们简要的回顾前文:《第1章 多线程安全性与风险》介绍了并发编程,在维护难度、性能以及活跃性三个方面,所带来的风险与优势;《第2章影响线程安全性的原子性和加锁机制》...

Diligence is the mother of success. 283

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Camera2Demo

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

Java enum不是语法糖:类型安全与工程实践指南

枚举(enum)是编程语言中用于定义有限、固定值集合的基础类型机制,在Java中远不止是常量替代品。其核心原理在于编译期类型约束、运行时不可变性与JVM级单例保障,构成强类型系统的底层支柱。技术价值体现在消除魔法值、防止跨域误用、支持策略封装与序列化定制等关键工程能力。典型应用场景包括订单状态管理、支付策略分发、设备心跳协议及配置元数据绑定。尤其在高可靠性系统中,合理使用enum可显著降低IllegalArgumentException异常、字符串转换失败和状态逻辑错乱等高频问题,真正发挥其作为‘契约型数据

weixin_34331102的博客 420

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

并发编程实战-对象的共享

并发编程实战第三章笔记

qq_33924360的博客 658

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

【Java并发编程一】线程安全和共享对象

一、什么是线程安全   当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用代码代码不必作其他的协调,这个类的行为仍然是正确的,那么称这个类是线程安全的。   内部锁   Java提供了强制性的内置锁机制:synchronized块。一个synchronized块有两个部分:锁对象的引用,以及这个锁保护的代码块。执行线程进入syn...

dengduoya4019的博客 257

java final语义_Java中final关键字的两层语义

一、final的基本语义final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)当用final修饰一个类时,表明这个类不能被继承。当用final修饰一个方法时,表明这个方法不能被重写。当用final修饰一个变量时,表明这个变量初始化后就不能再被修改。对于final类,从设计的角度来讲,将类设计为final是不希望这个类被继承,从而对这个类进行修改。比如String类。对于final方法...

weixin_39910963的博客 280

java中final与volatile-线程安全问题

在线程安全问题中final主要体现在安全发布问题上,在这里先讲一下什么事安全发布,在《java并发编程实践》一书中有讲,不过看起来挺难懂的…. public class Holder { private int n; public Holder(int n) { this.n = n; } public void assertSanity() {

THE___BEST的专栏 4198

天际线java_java中的final和volatile详解

相比synchronized,final和volatile也是经常使用的关键字,下面聊一聊这两个关键字的使用和实现1.使用final使用:修饰类表示该类为终态类,无法被继承修饰方法表示该方法无法重写,编译器可以内联编译修饰对象表示该对象引用一旦初始化后,无法被修改将参数传递到匿名内部类中,参数需要声明为final,其实外部类对与匿名内部类来说就是一个闭包,而java在匿名内部类中拷贝了一份,没有实...

weixin_26945061的博客 301

从Java内存模型理解synchronized、volatile和final关键字

你是否真正理解并会用volatile, synchronized, final进行线程间通信呢,如果你不能回答下面的几个问题,那就说明你并没有真正的理解: 1、对volatile变量的操作一定具有原子性吗?(原子操作是不需要synchronized。所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何线程切换) 2、synchronized所谓的加锁

Hopefully Sky的博客 4715

java中的final和volatile详解

  相比synchronized,final和volatile也是经常使用的关键字,下面聊一聊这两个关键字的使用和实现 1.使用   final使用: 修饰类表示该类为终态类,无法被继承 修饰方法表示该方法无法重写,编译器可以内联编译 修饰对象表示该对象引用一旦初始化后,无法被修改 将参数传递到匿名内部类中,参数需要声明为final,其实外部类对与匿名内部类来说就是一个闭...

dej2011的博客 1180

java属性为什么不能同时被final volatile 修饰

volatile是一个类型修饰符,它是被设计用来修饰被不同线程访问和修改的变量,可以被异步的线程所修改。 volatile修饰的变量是放到共享内存中的,可以让所有的线程获取和修改。 final必须对它赋予初值并且不能修改它。...

qq_42093488的博客 2204

原理解析_线程同步工具三剑客原理解析

说在前面前期回顾sharding-jdbc源码解析更新完毕spring源码解析 更新完毕spring-mvc源码解析 更新完毕spring-tx源码解析 更新完毕spring-boot源码解析 更新完毕rocketmq源码解析 更新完毕dubbbo源码解析 更新完毕netty源码解析 更新完毕spring源码架构更新完毕spring-mvc源码架构更新完毕spring-boot源码架构...

weixin_32702015的博客 248

《java并发编程实战》读笔 基础部分

《java并发编程实战》读笔 基础部分

lylhjh的博客 679

关于java中final关键字与线程安全性

在Java5中,final关键字是非常重要而事实上却经常被忽视其作为同步的作用。本质上讲,final能够做出如下保证:当你创建一个对象时,使用final关键字能够使得另一个线程不会访问到处于“部分创建”的对象,否则是会可能发生的。这是 因为,当用作对象的一个属性时,final有着如下的语义: 当构造函数结束时,final类型的值是被保证其他线程访问该对象时,它们的值是可见的 为什么是...

weixin_30482383的博客 511
上一篇: 带你读懂《Java并发编程》:第3章 助于线程安全的三剑客:final&valitale&线程封闭...
下一篇: 一文读懂《Effective Java》第5条:避免创建不必要的对象 & 性能优化
后台技术汇
博客等级 码龄11年 670粉丝 531原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

后台技术汇

对你的帮助,是对我的最好鼓励。

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

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

打赏作者

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

抵扣说明:

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

余额充值