-
java并发,操作i++,一个诡异的问题!3
源代码
public class Test { public static void main(String[] args) { final TestRun run = new TestRun(); Thread thread = new Thread(run); Thread thread2 = new Thread(run); thread.start(); thread2.start(); } } class TestRun implements Runnable { public Integer i = 0; public Object lock = new Object(); @Override public void run() { synchronized (i) { i++; System.out.println("step1:" + i); i++; System.out.println("step2:" + i); } } }
运行的结果。按理说,锁住了i对象,同步快中的内容顺序执行,结果为:
step1:1
step2:2
step1:3
step2:4
但结果却是:
step1:1
step1:2
step2:3
step2:4
或者
step1:1
step2:3
step1:2
step2:4
貌似没有锁住。
当改为synchronized (lock){
……
}
结果就正常了!
为什么????锁住对象了,不能对对象进行操作吗?
问题补充:liuqing_2010_07 写道加锁失败。
不明白,详细解释下?好吗?2012年4月04日 18:42
3个答案 按时间排序 按投票排序
-
采纳的答案
原因是Java的自动封箱和解箱操作在作怪。
这里的i++实际上是i = new Integer(i+1),所以执行完i++后,i已经不是原来的对象了,同步块自然就无效了。
其它基本类型的封装类,如Short、Long等等也不能作为同步对象2012年4月05日 05:22
-
小哀同学 已经道出天机。通过反编译代码来看这个问题。
// Decompiled by DJ v2.9.9.60 Copyright 2000 Atanas Neshkov Date: 2012-4-5 13:09:35 // Home Page : http://members.fortunecity.com/neshkov/dj.html - Check often for new version! // Decompiler options: packimports(3) // Source File Name: Airplane.java package test; import java.io.PrintStream; class TestRun implements Runnable { TestRun() { i = Integer.valueOf(0); lock = new Object(); } public void run() { synchronized(i) { i = Integer.valueOf(i.intValue() + 1); System.out.println((new StringBuilder("step1:")).append(i).toString()); i = Integer.valueOf(i.intValue() + 1); System.out.println((new StringBuilder("step2:")).append(i).toString()); } } public Integer i; public Object lock; }
i = Integer.valueOf(i.intValue() + 1);
在这里i已经变为新的对象。所以当线程2进入时临界区的对象i为新的没有加锁的对。
所以线程2能够闯入。加锁失败。在这里这种加锁方法本身就是不好的。直接用lock就行了。你可以Integer ii = new Integer (0); synchronized(i)
像上面那样也是没有问题的。
你遇到的这种现象属于“临界区资源泄漏”。
2012年4月05日 13:22
相关推荐
5. **Netty**:Netty是一个高性能的异步事件驱动的网络应用程序框架,常用于创建高效的服务器和客户端。了解Netty的Channel、EventLoop、ByteBuf等核心概念,以及其非阻塞I/O模型。同时,理解Netty如何处理HTTP、...
### Java并发知识点详解 ...综上所述,Java并发编程涉及到诸多复杂因素,包括线程的创建与管理、数据的一致性问题以及Java内存模型的细节等。理解这些概念是实现高性能、高可靠性的多线程应用的基础。
i++操作是一个典型的非原子操作,它包括三个步骤:读取、修改、写回。在多线程环境下,如果多个线程同时执行i++操作,可能会导致结果不正确。 例如,使用一个线程i++,另一个线程i–and,最后得到的结果可能不为0。...
《Java并发编程实践》是一本深入探讨Java多线程与并发编程的经典著作,其源码提供了丰富的示例,帮助读者理解和应用并发编程的核心概念。在这些文件中,我们可以看到多种并发设计模式和策略的实际运用,下面将逐一...
5. **非阻塞I/O(NIO)**:NIO(New Input/Output)提供了一种不同于传统阻塞I/O模型的机制,允许程序在数据准备就绪时才进行读写操作,提高了高并发I/O性能。Java NIO库包括Selector(选择器)、Channel(通道)和...
《Java并发实战编程》是一本深入探讨Java多线程编程技术的专业书籍,旨在帮助开发者理解和掌握并发编程的核心概念和最佳实践。并发编程是现代软件开发中的关键领域,尤其是在多核处理器普及的今天,利用线程并行执行...
Java并发编程是Java开发中的重要领域,它涉及到多线程、同步机制、线程池以及并发集合等核心概念。在Java中,并发编程是提高系统性能和资源利用率的关键技术,尤其是在处理大量I/O操作或者计算密集型任务时。本文将...
Java并发工具类是Java平台提供的一系列用于处理多线程并发问题的类和接口,它们在`java.util.concurrent`包中。并发问题主要包括资源竞争、死锁、活锁以及饥饿等,合理使用并发工具可以有效地提高程序的并发性能并...
3. **有序性问题**(Happens-Before原则):这是关于程序执行顺序的概念,即一个操作的执行结果是否对另一个操作可见,以及能否确保这两个操作发生的相对顺序。在并发程序中,如果不能保证操作的顺序,那么可能会...
线性化(Linearizability)是指在并发环境中,对数据结构的操作表现为似乎有一个全局的顺序,尽管实际上操作可能在不同的处理器核心上并行执行。这种特性使得并发数据结构的设计和实现非常复杂,但同时也是提升系统...
- **程序次序法则**:如果一个操作在另一个操作之前发生,那么第一个操作的结果对第二个操作来说是可见的。 - **监视器法则**:解锁监视器的操作发生在随后对该监视器的锁定之前。 - **volatile变量法则**:对...
《Java并发编程英文版》是Doug Lea所著的一部关于Java并发编程的经典作品。Doug Lea是计算机科学领域的知名学者,尤其在并发编程、设计模式、软件工程等领域有深入的研究和独到的见解。本书在1996年首次出版,至今仍...
在接口自动化测试领域,Java、TestNG和数据库的结合是一个常用且强大的组合。这个压缩包“基于java+testng+数据库的接口自动化测试.zip”很可能包含了一套完整的接口自动化测试框架,用于验证后端服务的功能性和数据...
以下将详细讨论《JAVA并发编程实践》和《Java网络高级编程》两本书中涵盖的关键知识点。 首先,让我们关注并发编程。并发编程是现代多核处理器系统中不可或缺的一部分,它允许程序同时执行多个任务,从而提高系统...
Java并发是指在一个程序中同时运行多个线程的能力。每个Java程序至少包含一个线程,即启动时运行在`main`方法中的主线程。此外,在Java虚拟机(JVM)初始化过程中还会启动其他后台线程,这些线程的数量和类型取决于...
通过对Java并发库的解读,我们可以了解到Java为解决多线程环境下出现的各种问题提供了一系列工具和技术。从重排序的概念出发,我们探讨了如何使用`volatile`关键字以及`final`域来确保多线程程序的一致性和可见性。...
### Java并发编程与高并发解决方案知识点总结 #### 一、并发与高并发基本概念 ##### 1.1 并发 - **定义**: 指一个程序在同一时刻拥有两个或更多的线程,这些线程可以在单核或多核处理器上运行。 - **单核处理器上...
JavaSelector在Java NIO(非阻塞I/O)中扮演着关键角色,它允许程序同时监控多个通道(channels)的事件,例如连接请求、数据可用性或者关闭事件,而无需在一个单独的线程中轮询所有通道。这种机制极大地提高了处理...