`
lingqi1818
  • 浏览: 253427 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

java线程和锁的规范

阅读更多
概述
假如行为不同步在多线程环境下就会出现混乱。
在共享内存环境中读取一块由可能被多个线程更新的数据。那么就需要建立java内存模型。并且这个模型在不同的硬件架构中是类似的。
以下为原文:
The behavior of threads, particularly when not correctly synchronized, can be
confusing and counterintuitive. This chapter describes the semantics of multithreaded
programs; it includes rules for which values may be seen by a read of
shared memory that is updated by multiple threads. As the specification is similar
to the memory models for different hardware architectures, these semantics are
known as the Java programming language memory model. When no confusion
can arise, we will simply refer to these rules as "the memory model".

1. 锁
比较简单,同步由监视器实现,注意监视器关联的对象是哪个就可以了。
java.util.concurrent包提供了同步的其他方式。

2. 代码重排序问题
初始化r1=r2=0
Trace 17.1: Surprising results caused by statement reordering - original code
Thread 1 Thread 2
1: r2 = A; 3: r1 = B;
2: B = 1; 4: A = 2;
Trace 17.2: Surprising results caused by statement reordering - valid compiler
transformation
Thread 1 Thread 2
B = 1; r1 = B;
3. r2 = A; A = 2;

初始化rp=q,p.x=0
Trace 17.3: Surprising results caused by forward substitution
Thread 1 Thread 2
r1 = p; r6 = p;
r2 = r1.x; r6.x = 3;
r3 = q;
r4 = r3.x;
r5 = r1.x;
Trace 17.4: Surprising results caused by forward substitution
Thread 1 Thread 2
r1 = p; r6 = p;
r2 = r1.x; r6.x = 3;
r3 = q;
r4 = r3.x;
r5 = r2;

4. 内存模型

java 内存模型 ( java memory model )
根据Java Language Specification中的说明, jvm系统中存在一个主内存(Main Memory或Java Heap Memory),Java中所有变量都储存在主存中,对于所有线程都是共享的。

每条线程都有自己的工作内存(Working Memory),工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。





其中, 工作内存里的变量, 在多核处理器下, 将大部分储存于处理器高速缓存中, 高速缓存在不经过内存时, 也是不可见的.

jmm怎么体现 可视性(Visibility) ?
在jmm中, 通过并发线程修改变量值, 必须将线程变量同步回主存后, 其他线程才能访问到.

jmm怎么体现 有序性(Ordering) ?
通过java提供的同步机制或volatile关键字, 来保证内存的访问顺序.

缓存一致性(cache coherency)

什么是缓存一致性?
它是一种管理多处理器系统的高速缓存区结构,其可以保证数据在高速缓存区到内存的传输中不会丢失或重复。(来自wikipedia)

举例理解:
假如有一个处理器有一个更新了的变量值位于其缓存中,但还没有被写入主内存,这样别的处理器就可能会看不到这个更新的值.

解决缓存一致性的方法?
a, 顺序一致性模型:
要求某处理器对所改变的变量值立即进行传播, 并确保该值被所有处理器接受后, 才能继续执行其他指令.

b, 释放一致性模型: (类似jmm cache coherency)
允许处理器将改变的变量值延迟到释放锁时才进行传播.
happens-before ordering
a, 在程序顺序中, 线程中的每一个操作, 发生在当前操作后面将要出现的每一个操作之前.
b, 对象监视器的解锁发生在等待获取对象锁的线程之前.
c, 对volitile关键字修饰的变量写入操作, 发生在对该变量的读取之前.
d, 对一个线程的 Thread.start() 调用 发生在启动的线程中的所有操作之前.
e, 线程中的所有操作 发生在从这个线程的 Thread.join()成功返回的所有其他线程之前.

以下为原文:
The rules for happens-before are:


Program order rule. Each action in a thread happens-before every action in that thread that comes later in the program order.



Monitor lock rule. An unlock on a monitor lock happens-before every subsequent lock on that same monitor lock.



Volatile variable rule. A write to a volatile field happens-before every subsequent read of that same field.



Thread start rule. A call to Thread.start on a thread happens-before every action in the started thread.



Thread termination rule. Any action in a thread happens-before any other thread detects that thread has terminated, either by successfully return from Thread.join or by Thread.isAlive returning false.



Interruption rule. A thread calling interrupt on another thread happens-before the interrupted thread detects the interrupt (either by having InterruptedException tHRown, or invoking isInterrupted or interrupted).



Finalizer rule. The end of a constructor for an object happens-before the start of the finalizer for that object.



Transitivity. If A happens-before B, and B happens-before C, then A happens-before C.



单例的 DCL多线程延迟加载示例:
Java代码 
1. Class Foo  
2. {  
3. Private Resource res = null;  
4. Public Resource getResource()  
5. {  
6. If (res == null)  
7. {  
8.        //只有在第一次初始化时,才使用同步方式.  
9. synchronized(this)  
10. {  
11. if(res == null)  
12. {  
13. res = new Resource();  
14. }  
15. }  
16. }  
17. return res;  
18. }  
19. } 


Double-Checked Locking看起来是非常完美的。但是很遗憾,根据Java的语言规范,上面的代码是不可靠的。

出现上述问题, 最重要的2个原因如下:
1, 编译器优化了程序指令, 以加快cpu处理速度.
2, 多核cpu动态调整指令顺序, 以加快并行运算能力.

问题出现的顺序:
1, 线程A, 发现对象未实例化, 准备开始实例化
2, 由于编译器优化了程序指令, 允许对象在构造函数未调用完前, 将 共享变量的引用指向 部分构造的对象, 虽然对象未完全实例化, 但已经不为null了.
3, 线程B, 发现部分构造的对象已不是null, 则直接返回了该对象.

不过, 一些著名的开源框架, 包括jive,lenya等也都在使用DCL模式, 且未见一些极端异常.
说明, DCL失效问题的出现率还是比较低的.
接下来就是性能与稳定之间的选择了?

DCL的替代 Initialize-On-Demand :
Java代码 
1. public class Foo {  
2.     // 似有静态内部类, 只有当有引用时, 该类才会被装载  
3.     private static class LazyFoo {  
4.        public static Foo foo = new Foo();  
5.     }  
6.    
7.     public static Foo getInstance() {  
8.        return LazyFoo.foo;  
9.     }  
10. } 



参考资料:jls3.0
http://javatar.iteye.com/blog/144763


  • 大小: 39.7 KB
分享到:
评论

相关推荐

    java并发规范(线程及锁).docx

    Java并发编程规范是Java开发中不可或缺的一部分,遵循这些规范能够帮助我们编写出更稳定、高效且易于维护的多线程程序。以下是对给定文件中提及的一些关键知识点的详细解释: 1. **指定线程名称**:在创建线程或...

    JAVA线程深入了解

    ### JAVA线程深入了解 #### 一、JAVA线程启动方式详解 ##### 1. 利用`Thread`类的子类启动线程 在Java中,可以通过继承`Thread`类来创建一个新的线程。这种方式相对直观,易于理解。具体做法是创建一个`Thread`类...

    java线程-Java内存模型

    Java线程-Java内存模型是Java并发编程中的关键概念,它描述了多个线程如何共享和访问内存资源,以及如何保证数据的一致性和安全性。Java内存模型(JMM)是Java虚拟机规范的一部分,用于定义程序中各个线程对共享变量...

    Java线程安全.docx

    Java线程安全是指在多线程并发编程中,如何确保线程安全地访问和修改共享资源的问题。Java内存模型(JMM)是Java虚拟机(JVM)定义的内存模型,旨在屏蔽底层平台的内存管理细节,提供了一个统一的内存模型规范。 ...

    Java多线程和并发知识整理

    Java线程有新建、可运行、运行、阻塞、等待、超时等待和终止等状态。 2.2 使用方式 可以通过`Thread`类或`Runnable`接口创建线程,使用start()方法启动。 2.3 基础机制 包括线程调度、上下文切换等。 2.4 中断 线程...

    Java语言规范 基于Java SE 8

    全书从Java基础的文法、类型、变量到高级特性lambda表达式、线程与锁等进行了详尽圃述。该规范针对每一项语言特性都给出了代表性的示例程序,以帮助读者更容易地理解和掌握这些特性。通过阅读本规范,可以全面系统地...

    Java线程安全.pdf

    Java线程安全主要涉及到的是多线程环境下对共享资源的管理和控制,以确保并发执行的线程能正确地访问和修改数据,避免出现数据不一致或者竞态条件等问题。Java内存模型(JMM)是Java虚拟机规范的一部分,它定义了...

    Java编码规范.docx

    在并发处理中,Java 编码规范规定了对多线程的基本规则,如线程安全、锁机制等。这些规则可以确保多线程程序的正确性和可靠性。 在控制语句中,Java 编码规范规定了对 if、switch、循环等语句的使用规则。这些规则...

    Java线程创建与管理:深入理解与实践指南

    Java线程的创建和管理是一个复杂但非常重要的主题。通过本文的介绍,读者应该对Java中创建线程的不同方式、线程的生命周期管理、线程安全和线程间通信有了更深入的理解。掌握这些知识,可以帮助开发者编写出更高效、...

    java虚拟机规范 Java SE7

    Java SE7引入了Fork/Join框架,优化了并行计算,同时对锁和同步进行了改进,如轻量级锁和自旋锁。 8. **动态类型**:Java SE7引入了`钻石操作符`(`<>`),简化了匿名内部类和泛型的使用,以及`try-with-resources`...

    Java语言规范

    全书从Java最基础的文法、类型、变量到高级特性lambda表达式、线程与锁等进行了详尽阐述。该规范针对每一项语言特性都给出了代表性的示例程序,以帮助读者更容易地理解和掌握这些特性。通过阅读本规范,可以全面系统...

    JAVA教程之线程篇

    深入理解Java线程前,需澄清几个关键术语: 1. **Java**:起初被视为一种编程语言,但发展至今,Java已演变成一个全面的平台,由编程语言、API和虚拟机规范三部分构成。线程特性贯穿于Java平台的每一个层面,确保了...

    Java多线程和并发知识点详细总结_并发_java_

    10. 内存模型与垃圾收集:Java内存模型(JMM)规范了线程间的通信和内存访问,垃圾收集则自动回收不再使用的内存,避免内存泄露。 Java多线程和并发知识点的详细总结通常会涵盖以下内容: 1. 线程的生命周期:新建...

    java线程编程方面-讲解.pdf

    下面将详细解释这三个概念及其在Java线程编程中的相关知识点。 **原子性**: 原子性是指在一次操作或者一系列操作中,要么全部执行,要么全部不执行,中间不会被其他线程打断。这是并发编程中保证数据一致性的基础...

    java虚拟机规范7和8

    在JVM 8中,对锁的实现和线程同步机制进行了优化,如使用CAS(Compare and Swap)操作减少锁的开销。 7. **类型推断** 在JVM 8中,Java引入了Lambda表达式和方法引用来简化多参数匿名内部类的编写,这依赖于类型...

    多线程实现文件下载,代码规范明了

    在Java或C#等支持多线程的编程语言中,线程是程序执行的最小单元,每个线程都有自己的栈空间,可以独立执行任务。在文件下载场景中,我们可以创建多个线程,每个线程负责下载文件的一部分。 接下来,我们将介绍三种...

    JSR133中文版.pdf

    总的来说,该文档是Java内存模型和线程规范的一个详尽的解释,它定义了Java平台中多线程编程的规则和行为,包括锁的机制、happens-before原则、内存模型的不同近似模型,以及final字段的语义等。这本规范对于Java...

    Java 多线程同步 锁机制与synchronized深入解析

    线程获取锁的顺序是不确定的,Java规范中并未保证这一点。线程调度的细节由JVM决定,可能存在一定的非确定性。 同步代码块提供了更多的灵活性。它可以指定锁定的对象,这就像是用不同房子的钥匙打开同一个房子的...

    Java多线程高级技术.pdf

    在实际的学习和开发过程中,我们应当根据上下文和Java语言规范对这些错误进行修正和理解。例如,文档中的“List”应该是“ArrayList”,而“list.resize”可能实际上是指向“list.setSize”。 综上所述,文档主要...

Global site tag (gtag.js) - Google Analytics