`

【转】同步块和同步方法

阅读更多
打个比方:一个object就像一个大房子,大门永远打开。房子里有很多房间(也就是方法)。这些房间有上锁的(synchronized方法),和不上锁之分(普通方法)。房门口放着一把钥匙(key),这把钥匙可以打开所有上锁的房间。另外我把所有想调用该对象方法的线程比喻成想进入这房子某个房间的人。所有的东西就这么多了,下面我们看看这些东西之间如何作用的。

在此我们先来明确一下我们的前提条件。该对象至少有一个synchronized方法,否则这个key还有啥意义。当然也就不会有我们的这个主题了。

一个人想进入某间上了锁的房间,他来到房子门口,看见钥匙在那儿(说明暂时还没有其他人要使用上锁的房间)。于是他走上去拿到了钥匙,并且按照自己的计划使用那些房间。注意一点,他每次使用完一次上锁的房间后会马上把钥匙还回去。即使他要连续使用两间上锁的房间,中间他也要把钥匙还回去,再取回来。

因此,普通情况下钥匙的使用原则是:“随用随借,用完即还。”

这时其他人可以不受限制的使用那些不上锁的房间,一个人用一间可以,两个人用一间也可以,没限制。但是如果当某个人想要进入上锁的房间,他就要跑到大门口去看看了。有钥匙当然拿了就走,没有的话,就只能等了。

要是很多人在等这把钥匙,等钥匙还回来以后,谁会优先得到钥匙?Not guaranteed。象前面例子里那个想连续使用两个上锁房间的家伙,他中间还钥匙的时候如果还有其他人在等钥匙,那么没有任何保证这家伙能再次拿到。(JAVA规范在很多地方都明确说明不保证,象Thread.sleep()休息后多久会返回运行,相同优先权的线程那个首先被执行,当要访问对象的锁被释放后处于等待池的多个线程哪个会优先得到,等等。我想最终的决定权是在JVM,之所以不保证,就是因为JVM在做出上述决定的时候,绝不是简简单单根据一个条件来做出判断,而是根据很多条。而由于判断条件太多,如果说出来可能会影响JAVA的推广,也可能是因为知识产权保护的原因吧。SUN给了个不保证就混过去了。无可厚非。但我相信这些不确定,并非完全不确定。因为计算机这东西本身就是按指令运行的。即使看起来很随机的现象,其实都是有规律可寻。学过计算机的都知道,计算机里随机数的学名是伪随机数,是人运用一定的方法写出来的,看上去随机罢了。另外,或许是因为要想弄的确定太费事,也没多大意义,所以不确定就不确定了吧。)

再来看看同步代码块。和同步方法有小小的不同。

1.从尺寸上讲,同步代码块比同步方法小。你可以把同步代码块看成是没上锁房间里的一块用带锁的屏风隔开的空间。

2.同步代码块还可以人为的指定获得某个其它对象的key。就像是指定用哪一把钥匙才能开这个屏风的锁,你可以用本房的钥匙;你也可以指定用另一个房子的钥匙才能开,这样的话,你要跑到另一栋房子那儿把那个钥匙拿来,并用那个房子的钥匙来打开这个房子的带锁的屏风。

记住你获得的那另一栋房子的钥匙,并不影响其他人进入那栋房子没有锁的房间。

为什么要使用同步代码块呢?我想应该是这样的:首先对程序来讲同步的部分很影响运行效率,而一个方法通常是先创建一些局部变量,再对这些变量做一些操作,如运算,显示等等;而同步所覆盖的代码越多,对效率的影响就越严重。因此我们通常尽量缩小其影响范围。如何做?同步代码块。我们只把一个方法中该同步的地方同步,比如运算。

另外,同步代码块可以指定钥匙这一特点有个额外的好处,是可以在一定时期内霸占某个对象的key。还记得前面说过普通情况下钥匙的使用原则吗。现在不是普通情况了。你所取得的那把钥匙不是永远不还,而是在退出同步代码块时才还。

还用前面那个想连续用两个上锁房间的家伙打比方。怎样才能在用完一间以后,继续使用另一间呢。用同步代码块吧。先创建另外一个线程,做一个同步代码块,把那个代码块的锁指向这个房子的钥匙。然后启动那个线程。只要你能在进入那个代码块时抓到这房子的钥匙,你就可以一直保留到退出那个代码块。也就是说你甚至可以对本房内所有上锁的房间遍历,甚至再sleep(10*60*1000),而房门口却还有1000个线程在等这把钥匙呢。很过瘾吧。

在此对sleep()方法和钥匙的关联性讲一下。一个线程在拿到key后,且没有完成同步的内容时,如果被强制sleep()了,那key还一直在它那儿。直到它再次运行,做完所有同步内容,才会归还key。记住,那家伙只是干活干累了,去休息一下,他并没干完他要干的事。为了避免别人进入那个房间把里面搞的一团糟,即使在睡觉的时候他也要把那唯一的钥匙戴在身上。

最后,也许有人会问,为什么要一把钥匙通开,而不是一个钥匙一个门呢?我想这纯粹是因为复杂性问题。一个钥匙一个门当然更安全,但是会牵扯好多问题。钥匙的产生,保管,获得,归还等等。其复杂性有可能随同步方法的增加呈几何级数增加,严重影响效率。

这也算是一个权衡的问题吧。为了增加一点点安全性,导致效率大大降低,是多么不可取啊。
分享到:
评论

相关推荐

    深入探索Java中的同步机制:同步代码块与同步方法详解

    同步代码块和同步方法是Java中确保线程安全的重要机制。它们各有优缺点,适用于不同的场景。在实际开发中,开发者应该根据具体需求选择合适的同步机制。通过合理使用同步代码块和同步方法,可以有效地控制线程对共享...

    静态方法同步 与 非静态方法同步

    在Java中,同步是通过`synchronized`关键字实现的,它用于确保同一时间只有一个线程可以执行特定代码块。这有助于维护数据的完整性,特别是在多个线程可能同时修改同一对象的情况下。 1. 静态方法同步: 静态方法是...

    java多线程实现火车售票系统以及java中的同步的实现同步块和同步方法同时同步[归纳].pdf

    本篇将详细解释如何使用Java多线程来实现火车售票系统,并探讨Java中同步的实现,包括同步块(synchronized block)和同步方法(synchronized method)。 首先,火车售票系统的模拟通常是为了演示线程间的协作和...

    java 中同步方法和同步代码块的区别详解

    同步方法和同步代码块是Java中实现同步的主要方式,它们都用于解决线程安全问题,但有各自的特点和适用场景。 同步方法是通过在方法声明前加上`synchronized`关键字来实现的。例如: ```java public synchronized ...

    C#线程同步的几种方法

    对于整数类型的操作,`System.Threading.Interlocked`类提供了一种轻量级的线程同步解决方案,其中包含的方法如`Increment`, `Decrement`, `Exchange`和`CompareExchange`,能够在不使用锁的情况下实现线程安全的...

    java中synchronized(同步代码块和同步方法)详解及区别

    本篇文章将详细介绍`synchronized`的两种形式:同步代码块和同步方法,并分析它们的区别。 1. **同步代码块 (Synchronized Block)** 同步代码块的语法结构如下: ```java synchronized (object) { // 需要同步...

    java 同步方法

    例如,清单2中将同步代码块外移,先进行线程安全的预处理,然后在同步块内仅执行关键操作,如从HashMap中获取值。 2. **使用并发工具**:Java提供了一些并发工具类,如`java.util.concurrent`包中的`Atomic`类、`...

    Java同步代码块和同步方法原理与应用案例详解

    本篇文章将深入探讨Java同步代码块和同步方法的原理及其在实际应用中的案例,以实现一个简单的买票系统为例。 首先,我们需要理解“原子性”这个概念。在多线程环境中,原子性意味着一段代码在执行过程中不会被其他...

    【IT十八掌徐培成】Java基础第08天-03.多线程-同步代码块-同步方法.zip

    本教程将深入讲解Java中的多线程以及同步控制机制,特别是同步代码块和同步方法。 首先,我们要理解什么是线程。线程是程序执行的最小单位,一个进程中可以有多个线程并发执行。在Java中,可以通过实现`Runnable`...

    java 多线程同步方法的实例

    Java提供了多种机制来实现线程同步,主要包括synchronized关键字、wait()、notify()和notifyAll()方法以及ReentrantLock等。 1. **synchronized关键字**:这是Java中最基本的线程同步方式。它可以用于修饰方法或...

    异步时钟域同步化处理方法

    本文将深入探讨几种异步时钟域同步化处理的方法,以确保系统稳定性和可靠性。 首先,我们来理解一下什么是异步时钟域。在FPGA设计中,不同的模块或功能块可能由不同的时钟源驱动,这些时钟源的频率可能相同也可能...

    同步代码块(synchronized).zip

    在这个例子中,`increment()`和`decrement()`方法都用到了同步代码块,使得计数操作不会因线程并发而出现不正确的结果。 通过这两个示例,我们可以学习到同步代码块在实际编程中的应用,以及如何解决多线程环境下的...

    NET多线程同步方法详解

    Monitor类提供了Enter和Exit方法来获取和释放对象锁,确保同一时间只有一个线程能访问受保护的代码块,即临界区。与lock语句类似,但Monitor提供更多的灵活性,如TryEnter尝试获取锁、Wait使当前线程等待、Pulse和...

    libusb 块传输 同步传输 例程

    本例程主要关注的是libusb中的“块传输”和“同步传输”功能,这两种传输模式是USB通信中不可或缺的部分。下面我们将深入探讨这两个概念以及如何在libusb中实现它们。 首先,USB块传输(Bulk Transfer)是USB协议中...

    电信设备-传输同步广播块和RMSI的相关信息的方法及装置.zip

    在具体的方法和装置设计中,电信设备可能会采用各种策略来优化广播同步和RMSI的传输。例如,设备可能利用特定的同步信号或参考信号来实现精确的定时同步。此外,可能采用高效的编码和调制技术来增强广播信息的抗干扰...

    同步块线程的调用--java

    4. **wait()、notify()和notifyAll()**:这些是Object类的方法,可以在同步块中使用,用于线程间的通信。`wait()`会让当前线程等待,`notify()`或`notifyAll()`会唤醒等待的线程。 5. **volatile关键字**:虽然不是...

    25.线程的同步机制-synchronized同步语句-使用同步代码块解决同步方法的弊端.mp4

    在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。

    Java多线程-同步机制解决线程安全问题方式一:同步代码块

    当线程通过`synchronized`关键字进入同步代码块或同步方法时,它会获取对象的锁。如果锁已被其他线程持有,那么该线程将会被阻塞,直到锁被释放。锁的状态存储在对象头的Mark Word中,包括线程ID等信息。 三、同步...

    java使用datax增量同步代码

    6. **全量与增量切换**:DataX 允许你在同一份配置中灵活切换全量和增量同步。只需修改配置文件中的增量条件或移除条件即可实现。 值得注意的是,DataX 的可配置性非常强,它允许用户自定义 Reader 和 Writer,扩展...

    Java多线程同步具体实例讲解 .doc

    值得注意的是,同步块和同步方法的本质是一样的,都是通过获取对象的锁来实现同步。在同步块中,我们可以指定任何对象作为锁,而在同步方法中,锁默认是当前对象。在这个例子中,`sell()`方法使用`this`作为锁,而...

Global site tag (gtag.js) - Google Analytics