`
david.org
  • 浏览: 157168 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

线程安全性-volatile

阅读更多

今晚读了新同事关于P2P做种的Java 代码,Code风格很漂亮,但仔细多看几眼,就会出现瑕疵。其中有一点关于线程的安全性,还是觉得有必要拿出来说说。

代码的意图是利用一个标识性Boolean变量来控制一个线程的开启(Service)与结束(Shutdown)。
A类:
private Boolean isStarted = false;

public void start () {
	isStarted = true;
	while(isStarted){
		// do something
}
}

public void stop() {
	isStarted = false;
}


看完上段代码,不少朋友应该知道问题出现在了什么地方。没错,A类是线程不安全的,其他线程对isStarted 变量的修改,对于A线程类来说,会发生不可预知的问题。

对象的可见性
在一个单线程化的环境里,如果向一个变量先写入值,然后在没有写干涉的情况下读取这个变量,那么会得到预料之中的相同返回值。但是当读和写发生在不同的线程中时,通常不能保证读线程及时地读取其他线程写入的值,甚至可以说根本不可能。为了确保跨线程写入的内存可见性,需使用同步机制。
private static boolean ready;
	private static int number;

	private static class ReaderThread extends Thread
	{
		public void run() {
			while(!ready)
			Thread.yield();
			System.out.println(number);
		}
	}

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


上段代码看起来最终执行的结果会是输出42,但事实上,它很有可能会输出0,甚至永远不会终止。这是因为没有使用恰当的同步机制。也就是说没能保证number和ready 的值对读线程是可见的。

很奇怪吧,但事实确实如此,因为对于读线程来说,ready 的值可能永远不可见,甚至会输出0,因为在对number赋值之前,主线程就已经写入ready,并对读线程写见。Okay,这是一种“重排序”(在单线程中,只要重排序不会对结果产生影响,那就不能完全保证其中的操作一定是按照程序所写的那样。 这是JVM的编译器为了充分利用多核处理器性能而设计的,这方面不了解的朋友可以了解一下Java存储模型)。

这种情况在我的项目中发生,是非常的可怕的。幸运的是被发现了,且Java提供了一个简单的方法来避免这个问题。

Volatile变量

Java提供了一种同步的弱形式(这也是一种以锁的形式出现的):volatile变量。它确保对一个变量的更新以可预见的方式通知其他的线程。当一个域声明为volatile类型后,编译器和运行时会监视这个变量:它是共享的,而且对它的操作不会与其他的内存操作一起被重排序。
volatile boolean asleep;
	...
		while (!asleep)
		{
			countSomeSheep();
		}

一个典型的volatile变量应用:检查状态标记,以确定是否退出一个循环。为了保证执行检查的线程能够注意到asleep已被其他线程修改。Asleep标记就必须为volatile。Okay, 这里同样可以使用锁来代替volatile,一样能保证对asleep变量修改的可见性。

最后说说volatile与锁的区别:
加锁可以保证可见性与原子性,然而volatile变量只能保证可见性
分享到:
评论

相关推荐

    Java多线程与线程安全实践-基于Http协议的断点续传

    总之,Java多线程与线程安全的实践是一个复杂而深入的话题,结合HTTP协议的断点续传,我们需要综合运用各种并发控制机制和优化技术,确保程序的稳定性和效率。通过这个毕业设计项目,你可以深入了解并掌握这些关键...

    Java 多线程与并发(5-26)-关键字- volatile详解.pdf

    而`volatile`关键字的使用,可以禁止这种重排序,保证了初始化的正确顺序,从而避免线程安全问题。 **二、实现可见性** 可见性是指当一个线程修改了共享变量的值,其他线程能够立即看到这个修改。在没有同步机制的...

    基于Java的多线程与线程安全实践-基于Http协议的断点续传.zip

    Java提供了多种机制来保证线程安全,如synchronized关键字、volatile变量、Lock接口(如ReentrantLock)以及Atomic类等。synchronized用于锁定代码块或方法,防止多个线程同时执行;volatile确保了多个线程间对变量...

    JAVA多线程与线程安全实践-基于Http协议的断点续传.rar

    在Java编程中,多线程和线程安全是核心概念,尤其在开发高效并发应用程序时。本项目"JAVA多线程与线程安全实践-基于Http协议的断点续传"探讨了如何在Java中实现多线程以及如何确保线程安全,特别是在处理HTTP协议的...

    Java多线程与线程安全实践-基于Http协议的断点续传.zip

    综上所述,"Java多线程与线程安全实践-基于Http协议的断点续传"项目涵盖了Java并发编程、HTTP协议的高级应用以及网络传输的安全性。通过学习和实践这个项目,开发者可以深入了解如何在实际场景中有效利用多线程和...

    Java多线程与线程安全实践-基于Http协议的断点续传.rar

    此外,使用volatile关键字可以确保变量在多线程环境中的可见性和有序性。 **3. Http协议的断点续传** 断点续传是一种在下载或上传大文件时中断后能够从上次中断的位置继续传输的技术。基于Http协议的断点续传通常...

    Java多线程与线程安全实践-基于Http协议.zip

    在Java编程中,多线程和线程安全是核心概念...总之,Java多线程与线程安全是提升应用程序性能和稳定性的关键。通过深入学习和实践,我们可以有效地在基于HTTP协议的环境中应用这些技术,构建出高效、健壮的多线程应用。

Global site tag (gtag.js) - Google Analytics