`
JohnShen0708
  • 浏览: 59449 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java多线程 - 不要同步Boolean常量

阅读更多

在JAVA中通过synchronized语句可以实现多线程并发。使用同步代码块,JVM保证同一时间只有一个线程可以拥有某一对象的锁。锁机制实现了多个线程安全地对临界资源进行访问。

 

同步代码写法如下:

 

代码1:

Object obj = new Object();
...
synchronized(obj) {
  //TODO: 访问临界资源
}

 

 

JAVA的多线程总是充满陷阱,如果我们用Boolean作为被同步的对象,可能会出现以下两种情况:

 

一. 以为对一个对象加锁,实际同步的是不同对象。

 

代码2:

 

private volatile Boolean isTrue = false;

publich void aMethod() {
  ...
  synchronized(isTrue) {
    isTrue = !isTrue;
    //TODO: 访问临界资源
    isTrue = !isTrue;
  }
  ...
}

 咋一看上面的代码没有问题,由于使用了synchronized(isTrue)同一时间只能有一个线程访问临界资源,但事实并不是这样。因为false和true这两个常量对应着两个不同的对象。当isTrue产生变化时,很可能导致不同的线程同步了不同的对象。JAVA的自动装箱会将false变为Boolean.FALSE,将true变为Boolean.TRUE(同时这也说明了此处若将false改为Boolean.FALSE其结果也是一样的)。写一个以上情况的测试代码如下:

 

代码3:

 

public class BooleanTest {
	
	private volatile Boolean isTrue = Boolean.FALSE; //此处用false也一样
	
	public void aMethod() {
		for(int i=0;i<10;i++) {
			Thread t = new Thread() {
				public void run() {
					synchronized(isTrue) {
						isTrue = !isTrue;
						System.out.println(Thread.currentThread().getName() + " - isTrue=" + isTrue);
						try{
							Double ran = 1000 * Math.random();
							Thread.sleep(ran.intValue());
						}catch(InterruptedException e) {}
						
						if(!isTrue) System.out.println(Thread.currentThread().getName() + " - Oh, No!");

						isTrue = !isTrue;
					}
				}
			};
			t.start();
		}
	}
	
	public static void main(String... args) {
		BooleanTest bt = new BooleanTest();
		bt.aMethod();
	}
}

 运行以上代码,不时的会看到 " - Oh, No!",表示不同的线程同时进入到synchronized代码块中。

 

二. 以为同步的是不同对象,实际是一个对象。

 

有时候我们可能希望在多个对象上进行同步,如果使用了Boolean作为被同步对象,很可能会导致本来应该没有关系的两个同步块使用了相同对象的锁。示例如下:

 

代码4:

 

private volatile Boolean aBoolean = Boolean.FALSE;

private volatile Boolean anotherBoolean = false;

public void aMethod() {
  ...
  synchronized(aBoolean) {
    //TODO: 访问临界资源1
  }
  ...
}

public void anotherMethod() {
  ...
  synchronized(anotherBoolean) {
    //TODO: 访问临界资源2
  }
  ...
}

 假设原本aMethod和anotherMethod分别会被两组没有关系的线程调用。但是由于Boolean.FALSE和false指向的是同一个对象,可能导致对临界资源2的访问被临界资源1阻塞了(反之亦然)

 

以上两种情况说明,在使用同步块时,尽量不用使用Boolean对象作为被同步对象,不然可能会出现意想不到的问题,或者对以后的代码修改造成陷阱。

 

从此也可以看出,任何对常量的同步都是有风险的。如果一定要对 Boolean 进行同步,一定要用 new 操作符来创建 Boolean 对象。

分享到:
评论

相关推荐

    浅谈Java多线程编程中Boolean常量的同步问题

    在Java多线程编程中,确保...总之,Java多线程编程中,对`Boolean`常量的同步必须谨慎处理,避免因为自动装箱和对象引用的特性导致的同步失效。通过正确理解和使用同步机制,我们可以确保多线程环境下的数据一致性。

    CoreJava串讲---超好!

    8. **多线程**:Java支持多线程编程,通过Thread类和Runnable接口可以创建并管理多个并发执行的任务。理解和掌握线程同步、互斥锁、死锁等概念,有助于编写高效的并发程序。 9. **反射机制**:反射是Java的高级特性...

    《java开发宝典-陈丹丹、李银龙》源代码+课件PPT

    6. **多线程** - **线程的创建与启动**:Thread类和Runnable接口的使用。 - **同步机制**:synchronized关键字,wait(), notify(), notifyAll()方法的应用。 - **线程池**:ExecutorService, ThreadPoolExecutor...

    JAVA程序员必读--基础篇

    8. **多线程**:Java内置了对多线程的支持,可以创建和管理线程,理解线程同步和互斥的概念,如synchronized关键字和wait/notify机制。 9. **反射**:Java反射机制允许在运行时检查类的信息,动态创建对象和调用...

    java笔记--

    - **Runnable接口**:另一种实现多线程的方式。 - **同步机制**:synchronized关键字、wait()、notify()和notifyAll(),防止数据竞争。 15. **网络编程** - **Socket编程**:实现客户端-服务器通信。 - **URL和...

    java-core-test

    - 线程同步:synchronized关键字,wait(), notify(), notifyAll()方法,以及Lock接口的使用。 - 守护线程与线程池:理解守护线程的概念,以及ExecutorService线程池的创建与管理。 8. **反射机制** - 类的加载:...

    完整版Java全套入门培训课件 Java基础 01-Java概述(共31页).rar

    - 线程同步:synchronized关键字、wait()、notify()和notifyAll()方法,防止数据竞争。 14. **反射机制** - 在运行时动态获取类的信息并调用其方法,是Java强大的特性之一。 15. **Java标准库** - 包含大量预先...

    Java编程起步--推荐初学者使用

    10. **多线程**:Java内置了对多线程的支持,你可以通过实现Runnable接口或继承Thread类创建线程。理解同步机制,如synchronized关键字和wait/notify机制,是提高程序效率的关键。 11. **Java库和API**:Java标准库...

    JAVA面试题---基础

    16. **多线程**:Java内置了对多线程的支持,通过实现Runnable接口或继承Thread类创建线程。线程同步机制包括synchronized关键字、wait()、notify()和notifyAll()方法。 17. **反射**:反射机制允许程序在运行时...

    java习题-多选题

    在"java习题-多选题"这个主题中,我们可以深入探讨Java的基础概念、语法特性、多线程、异常处理、集合框架、IO流、网络编程等多个核心知识点。 1. **基础概念与语法**: - 类与对象:Java的核心是面向对象编程,...

    JAVA面试题-基础部分3

    - **线程同步**:包括synchronized关键字、Lock接口、volatile关键字等。 - **线程池**:ExecutorService、ThreadPoolExecutor和Executors的理解与应用。 7. **IO流与NIO** - **流的分类**:按照流向分为输入流...

    Java基础笔记-笔试用

    - 线程同步机制,如`synchronized`关键字、`wait()`, `notify()`, `notifyAll()`方法,避免并发问题。 11. **反射**: - 反射允许程序在运行时检查类、接口、字段和方法的信息,并动态调用方法。 12. **注解...

    想学java,新手学java,怎样才能学好java,java视频教程,零基础学习java--java学习指导文档.doc

    Java 多线程机制 - **线程创建方式**:继承 Thread 类、实现 Runnable 接口。 - **同步机制**:synchronized 关键字、ReentrantLock 等。 - **并发工具类**:如 ExecutorService、Semaphore 等。 - **线程安全问题...

    java-se基础练习代码 Java学习资料

    Java SE涵盖了核心的Java语法、数据类型、控制结构、类和对象、异常处理、多线程、输入输出、集合框架等关键概念。 1. **核心语法与数据类型**:Java的基础始于了解其语法结构,如变量声明、常量定义、运算符和...

    java50-52

    总结,"java50-52"可能涵盖的内容包括但不限于Java的基本语法、面向对象编程、异常处理、集合框架、多线程、并发控制、IO/NIO以及接口和继承等核心概念。这些主题是每个Java开发者都需要掌握的基础,并且对于深入...

    清华大学JAVA教程(清华JAVA教程的PPT)

    - 线程同步:synchronized关键字、wait()、notify()、notifyAll()。 - 线程池:ExecutorService、ThreadPoolExecutor、Future。 9. **网络编程** - Socket编程:客户端与服务器端的通信。 - URL与URLConnection...

    Java面试八股文001-Java-Java基础

    由于方法都是同步的,所以在多线程环境下使用较为安全,但这也导致了性能上的损失。 - **StringBuilder**:可变字符串,非线程安全。与StringBuffer类似,提供了丰富的字符串操作方法,但由于没有同步机制,因此在单...

    java-beginners-guide:赫伯特·希尔德(Herbert Schildt)撰写的“ Java初学者指南”中的练习

    这本指南深入浅出地讲解了Java的核心概念,包括语法、数据类型、控制结构、类与对象、异常处理、输入/输出、多线程以及集合框架等。通过书中提供的练习,读者可以巩固所学知识,提升实际编程能力。 1. **Java语法...

    java-lang包详解

    - **Thread**: 实现多线程的类,提供了线程的创建、控制和同步。 - **ThreadLocal**: 提供线程局部变量,每个线程都有自己的副本。 - **SecurityManager**: 安全管理器,用于实施安全策略。 - **Void**: 代表...

Global site tag (gtag.js) - Google Analytics