|
修饰符 volatile 的一处用武之地――访问共享变量
当数据在线程间被共享时,如何确保各个线程都能正确地访问它们和得到有效的数值。虽然JVM可以保证32位的数据读写是原子的(Atomic),不可分割,但存在这样的情况使我们不得不警惕:Java语言允许线程保存变量的私有专用副本(private working copy),这样各个线程就可以更高效地运行,当线程读写这些变量时,操作的实际是各自的副本,而非主存在中的正本,且只有在特定的同步点(而不是时刻),才与主内存中的正本进行一致化动作,就像我们打联网打游戏一样,大家看到的同步画面也是在若干个同步点进行了同步,嘿嘿。
比如会出现下面的情况,不同线程中都对同一个对象进行着动作:
线程一:调用变量AA的set方法,设置其值为10。
线程二:调用变量AA的set方法,设置其值为5。
线程一:调用AA的get方法,得到值5。(由于现在仍操作的是线程一的副本数据,尚未与主内存中的正本同步,这是可能出现的,因为我们不能保证它们何时肯定同步了,总有时间间隔的。)
问题就出现了,解决的办法至少有两种:
1.使用synchronized函数或代码段来访问变量AA。
2.将变量AA申明为volatile(易变的)
上述两种办法都将迫使变量与主内存中的正本一致化,不过它们还是有区别的:
――――同步(synchronized)――――――
优点:取得和释放lock时才进行与主内存正本的同步,如果有大量数据需要更新时,使用同步控制比用volatile的执行效率要高。
缺点:同步之后当然没有并发性了,各线程中的对象只能排队一个一个来调用同一方法或代码段。
――――volatile――――――――――――
优点:各线程可以并发运行。
缺点:由于被申明为volatile的变量在每次得到访问时,都会即时与主内存一致化,所以当有大量数据需要随时更新时,一致化需要一些代价。
还有一种情况,由于一般的JVM只提供了对32位数据的原子操作,所以当访问64位的long型数据时,就跨越了两个32位数据,就有可能出现当第一个线程写了前32位后,第二个线程抢先来修改了整个64位的数据,这后第一个线程再得以修改其后32位数据――唉,数据最后当然就怪了。
????????????????????????????????????????????????????????????????????????????????????????????????
Java同步机制浅谈――synchronized对代码作何影响
Java对多线程的支持与同步机制深受大家的喜爱,似乎看起来使用了synchronized关键字就可以轻松地解决多线程共享数据同步问题。到底如何?――还得对synchronized关键字的作用进行深入了解才可定论。
总的说来,synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。
在进一步阐述之前,我们需要明确几点:
A.无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
B.每个对象只有一个锁(lock)与之相关联。
C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
接着来讨论synchronized用到不同地方对代码产生的影响:
假设P1、P2是同一个类的不同对象,这个类中定义了以下几种情况的同步块或同步方法,P1、P2就都可以调用它们。
1. 把synchronized当作函数修饰符时,示例代码如下:
Public synchronized void methodAAA()
{
//….
}
这也就是同步方法,那这时synchronized锁定的是哪个对象呢?它锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却可以任意调用这个被加了synchronized关键字的方法。
上边的示例代码等同于如下代码:
public void methodAAA()
{
synchronized (this) // (1)
{
//…..
}
}
(1)处的this指的是什么呢?它指的就是调用这个方法的对象,如P1。可见同步方法实质是将synchronized作用于object reference。――那个拿到了P1对象锁的线程,才可以调用P1的同步方法,而对P2而言,P1这个锁与它毫不相干,程序也可能在这种情形下摆脱同步机制的控制,造成数据混乱:(
2.同步块,示例代码如下:
public void method3(SomeObject so)
{
synchronized(so)
{
//…..
}
}
这时,锁就是so这个对象,谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以这样写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它得是一个对象)来充当锁:
class Foo implements Runnable
{
private byte[] lock = new byte[0]; // 特殊的instance变量
Public void methodA()
{
synchronized(lock) { //… }
}
//…..
}
注:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。
3.将synchronized作用于static 函数,示例代码如下:
Class Foo
{
public synchronized static void methodAAA() // 同步的static 函数
{
//….
}
public void methodBBB()
{
synchronized(Foo.class) // class literal(类名称字面常量)
}
}
代码中的methodBBB()方法是把class literal作为锁的情况,它和同步的static函数产生的效果是一样的,取得的锁很特别,是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。
记得在《Effective Java》一书中看到过将 Foo.class和 P1.getClass()用于作同步锁还不一样,不能用P1.getClass()来达到锁这个Class的目的。P1指的是由Foo类产生的对象。
可以推断:如果一个类中定义了一个synchronized的static函数A,也定义了一个synchronized 的instance函数B,那么这个类的同一对象Obj在多线程中分别访问A和B两个方法时,不会构成同步,因为它们的锁都不一样。A方法的锁是Obj这个对象,而B的锁是Obj所属的那个Class。
小结如下:
搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程序。
还有一些技巧可以让我们对共享资源的同步访问更加安全:
1. 定义private 的instance变量+它的 get方法,而不要定义public/protected的instance变量。如果将变量定义为public,对象在外界可以绕过同步方法的控制而直接取得它,并改动它。这也是JavaBean的标准实现方式之一。
2. 如果instance变量是一个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。 这个时候就需要将get方法也加上synchronized同步,并且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。
/////////////////////////////////////////////////////////////////////////////
再次看了侯捷译的Thinking in Java第二版中文版,得到有关synchronized的如下信息:
1、synchronized关键字的作用域有二种:
1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;
2)是某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。
2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){/*区块*/},它的作用域是当前对象;
3、synchronized关键字是不能继承的,也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法;
|
相关推荐
从LLaMA到LLaMA-MoE:轻量级混合专家模型构建与实战指南
混合专家(Mixture-of-Experts, MoE)是一种先进的神经网络架构,其核心原理是通过门控网络动态地为不同输入选择不同的专家子网络进行计算,从而实现模型容量的指数级扩展,同时保持推理时的计算量基本不变。这种稀疏激活的特性赋予了MoE极高的技术价值,使其成为解决大模型训练与推理成本矛盾的关键技术之一,在自然语言处理、多模态学习等场景中展现出巨大潜力。本文聚焦于**LLaMA-MoE**这一具体实践,深入探讨了如何基于成熟的稠密模型(如LLaMA),通过**专家构建**与**持续预训练**两大关键
多线程——synchronized详解
互斥同步是一种最常见也是最主要的并发正确性保障手段。同步是指在多个线程并发访问共享数据时,保证共享数据在同一个时刻只被一条(或者是一些, 当使用信号量的时候)线程使用。而互斥是实现同步的一种手段,临界区(Critical Section)、互斥量 (Mutex)和信号量(Semaphore)都是常见的互斥实现方式。因此在“互斥同步”这四个字里面,互斥是因,同步是果;互斥是方法,同步是目的。在Java里面,最基本的互斥同步手段就是synchronized关键字。
OpenClaw国内大模型配置指南[源码]
本文详细介绍了OpenClaw(原名Moltbot、Clawdbot)开源个人AI助手项目在国内配置四大主流大模型(MiniMax、GLM、Kimi、Qwen)的完整方案。内容涵盖了API密钥获取、配置命令、模型选择及特性对比,并提供了通用配置脚本和配置文件修改方法。此外,还介绍了多模型切换与管理、配置验证与常见问题排查方法,以及最佳实践建议。文章最后总结了各模型的适用场景,并建议开发者根据业务需求选择合适的模型组合,以最大化AI助手的工作效率。
【多线程进阶】synchronized的总结
如果某一个资源被多个线程共享,为了避免因为资源抢占导致资源数据错乱,我们需要对线程进行同步,那么synchronized就是实现线程同步的关键字,可以说在并发控制中是必不可少的部分,今天就来看一下synchronized的使用和底层原理。
【多线程】synchronized 原理、使用、注意事项详解
synchronized是Java的一个关键字。来自官方的解释:Synchronized方法支持一种简单的策略,用于防止线程干扰和内存一致性错误:如果一个对象对多个线程可见,则对该对象变量的所有读或写操作都通过Synchronized方法完成。Synchronized保证同一时刻有且只有一条线程在操作共享数据,其他线程必须等待该线程处理完数据后再对共享数据进行操作。
多线程(synchronized)
synchronized是Java中的关键字,是一种同步锁。它修饰的对象有以下几种: 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象; 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象; 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象; 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的
Java多线程(二)——synchronized 详解
java多线程
多线程和Synchronized在其中的使用
多线程和Synchronized在其中的使用 一、多线程 需要提高任务执行效率,有多个任务且任务量大,或者多个任务中有会阻塞的情况 3.线程状态 1. 新建状态(New): 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。 2. 就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。 3. 运行状
【JavaSE】【多线程】synchronized和死锁
synchronized的语法,互斥,可重入; 死锁的成因与避免方案
多线程中synchronized作用
先看一个例子: //模仿火车售票系统,假设有4个售票点同时售票,我们可以把四个售票点定义为四个独立线程 class Test { public static void main(String[] args) { TestThread tt=new TestThread(); new Thread(tt).start(); //每一个售票点定义为一个
Synchronized在多线程下锁分析
先看下面程序,猜猜结果会是啥??? public class TestSynchronized implements Runnable { int b = 100; synchronized void m1() throws InterruptedException { b = 1000; Thread.sleep(500); //6 ...
Java多线程Synchronized心得
转载:http://www.vanjor.org/blog/2011/04/java-synchronized/ 两年前,在编写一个多线程采集器的时候,写了一篇心得《Java多线程Synchronized的注意细节》,但是随后的使用中,发现仍然没有完全分清场景与背后原理。现在随着实际应用,终于也有所新的成熟的理解了。 Synchronized是java语言级别内置的同步机制
多线程-概念及Synchronized锁
多线程-概念及Synchronized锁
多线程并发 synchronized
多线程—synchronized原理
锁分为细粒度(加锁范围小)和粗粒度(加锁范围大),当频繁使用细粒度锁加锁解锁时,JVM和编译器就会把多个细粒度锁优化成粗粒度锁,减少频繁的加锁解锁开销。,记录当前锁是哪个线程的,如果没有其他线程竞争锁,就不用真正的加锁,从而减少了加锁解锁的开销。3.synchronized的轻量级锁是自旋锁(基于CAS)实现,重量级锁是挂起等待锁(操作系统的mutex锁实现)。4.当锁竞争激烈时,此时自旋锁无法快速获得锁(就会一直浪费CPU资源),那就会升级为重量级锁。3.当偏向锁进入加锁状态时,也就是进入轻量级锁,
Java多线程——synchronized使用详解
一 前言 Java多线程是面试必考的知识点,哈哈,说的有点太绝对了,题外话不说那么多了,今天我们就来了解一下Java多线程中的synchronized。 synchronized相信大家都看过或者用过,synchronized是Java中的关键字,synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性,Java中每一个...
多线程之同步Synchronized
在java中synchronized是多个线程共享同一段代码的锁。 当有多个线程并发执行同一块代码块时,加锁可以让一段时间内只有一个线程在执行,保证了业务的原子操作。 例如下面: package andy.thread.traditional.test; /** * @author Zhang,Tianyou * @version 2014年11月8日 下午11:02:53 */
Java多线程进阶-深入synchronized与CAS
本篇笔记深入到更底层的实现,去探寻synchronized的锁升级机制和无锁编程CACAS (Compare-and-Swap) 是实现“乐观锁”的原子操作,也是JUC(`java.util.concurrent`)包中许多高性能类的幕后英雄。而 `synchronized`,这个我们最熟悉的关键字,其内部为了追求极致性能而进行的优化和演进,恰恰就是对CAS等思想的应用。可以说,理解了它们,我们才能真正看懂Java并发性能优化的精髓。
深入java多线程,多线程问题及synchronized的jvm原理
1、多线程安全新问题 什么时候会出现多线程问题以及出现多线程问题的条件有哪些,下面通过一个简单的例子来看下。 假如系统中需要生成累加不重复的数字,用来设置单号或流水号,我们通过一段简单的代码来实现: public class Thread4 { private int num; private int getNext() { return num++; } publi...
多线程——synchronized
多线程——C Java锁:作用就是解决多线程情况下多线程竞争数据造成的数据不安全 synchronized 修饰方法 synchronized{} 同步块 暗锁 synchronized安全的机制是:以性能换安全暗锁,自动释放锁, 执行同步结束,自动释放锁定资源,让其他线程可以执行。 使用synchronized的前提是:多个线程持有同一个对象的锁 Java线程最不爽的地方,线程的启动是不受程序员代码控制, 是由JVM控制的,即使设置线程优先级,也不能狗保证线程的启动 synchronize
使用synchronized解决多线程安全问题
目录 多线程安全问题: 解决多线程下安全问题的方法: 1.使用synchronized关键字: 2.对共享区代码使用显式Lock对象加锁: 什么是对象锁 使用浅显易懂的例子说明synchronized对象锁: 对象锁实现的方式: 什么是类锁: 使用synchronized关键字实现类锁: 总结: 多线程安全问题: 首先,在操作系统中线程是不拥有资...
548




被折叠的 条评论
为什么被折叠?



