Java并发编程杂记(2)

对象共享

synchronized 设定原子性确定临界区 + 内存可见性

要解决如下问题

防止一个线程在使用对象状态而另一个线程在修改对象状态;且当一个线程修改了对象状态后,对其他线程可见。

可见性

多线程情况下的读写,无法保证在执行读操作时能够看到其他线程写入的值 --- 同步机制解决

造成可见性的原因之一:指令重排序 ---- 产生失效数据

在32为机器执行double和long的问题

Jvm会拆分为两个32为的操作,在读取或写入时可能存在问题

读取到某个数的的高32位和另一个数的低32位     ---- (volatile)

加锁和可见性

加锁不仅是局限于互斥行为,还包括内存可见性。所有执行读写操作的线程都必须在同一个锁上同步。(happen-before)

volatile

保证变量更新通知其他线程,volatile变量确定为共享变量,不会进行指令重排序。而且不会被寄存器缓存。

volatile可见性,A线程写入一个volatile变量,B线程读取该变量。在写入之前对A可见的所有变量的值,在B读取变量以后对B也可见。

使用情况:在需要对可见性进行复杂判断时,不适用;适用于:自身状态可见性,确保引用状态的可见性,标识一些重要的程序生命周期事件的发生(init/destroy)

volatile不能保证递增操作的原子性。

加锁操作即可保证原子性又能保证可见性,volatile只能保证可见性

volatile使用总结

对变量的写入操作不依赖于变量当前值,或者确保单线程更新变量

该变量不会与其他状态变量一起纳入不变性条件中

(不变性条件:

对象创建以后其状态就不能修改

对象的所有域都是final类型

对象是正确创建的(在对象的创建期间,this引用没有溢出)

)

在访问变量时不需要加锁

发布与逸出

发布:对象能在当前作用域以外的地方使用

逸出:对象在不该被发布时发布了(如对象构建完成前)

不要在构造其中使用this引用逸出。

线程封闭

不使用共享数据 --- 线程封闭

单线程内访问数据

当某个对象封闭在一个线程中时,将自动实现线程安全,即使被封闭的对象本身不是线程安全的

(JDBC -- Connection,局部变量,ThreadLoacal)

Ad-hoc线程封闭

维护线程封闭完全由程序承担。,访问volatile变量时如可以保证时单线程写入,则可以实现特殊的线程封闭,且volatile可保证可见性,其他线程可以看到最新值

栈封闭

局部变量

不变性

不可变对象一定线程安全

final域

构造不可变对象

保证对象初始化过程的安全性,共享final对象时无需同步。

如果final类型域指向的是可变的对象,在访问这些域所指向对象的状态时仍然需要同步

安全的发布模式

在静态初始化函数中初始化一个对象引用。

将对象引用保存在volatile类型的域或者AtomicReferance对象中

将对象引用保存到某个正确构造对象的final类型域中

将对象引用保存到一个由锁保护的域中

保证安全发布的容器

Vector / synchronizedList

Hashtable / synchronizedMap / ConcurrentMap

CopyOnWriteArrayList / CopyOnWriteArraySet / synchronizedSet

BlockingQueue / ConcurrentLinkedQueue

其他数据传输机制:Future / Exchanger

事实不可变对象

发布以后的状态不会再改变状态的对象

对象的发布需求取决于可变性:

不可变对象可以任意的发布

事实不可变对象需要安全的发布

可变对象需要安全的发布,并且线程安全必须用某个锁保护起来

并发程序中使用共享对象的常用策略

线程封闭 --- 对象只有一个线程持有

只读共享 --- 可变对象/不可变对象的多线程读取

线程安全共享 --- 在线程安全内部实现同步

保护对象 --- 加锁

原文地址:https://www.cnblogs.com/DaveMo/p/12054251.html

时间: 2024-10-11 06:10:18

Java并发编程杂记(2)的相关文章

Java并发编程:Concurrent锁机制解析

.title { text-align: center } .todo { font-family: monospace; color: red } .done { color: green } .tag { background-color: #eee; font-family: monospace; padding: 2px; font-size: 80%; font-weight: normal } .timestamp { color: #bebebe } .timestamp-kwd

Java并发编程:Callable、Future和FutureTask(转)

Java并发编程:Callable.Future和FutureTask 在前面的文章中我们讲述了创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一个缺陷就是:在执行完任务之后无法获取执行结果. 如果需要获取执行结果,就必须通过共享变量或者使用线程通信的方式来达到效果,这样使用起来就比较麻烦. 而自从Java 1.5开始,就提供了Callable和Future,通过它们可以在任务执行完毕之后得到任务执行结果. 今天我们就来讨论一下Callabl

Java并发编程 Volatile关键字解析

volatile关键字的两层语义 一旦一个共享变量(类的成员变量.类的静态成员变量)被volatile修饰之后,那么就具备了两层语义: 1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的. 2)禁止进行指令重排序. 根据volatile的语义,我们可以看到,volatile主要针对的是并发三要素(原子性,可见性和有序性)中的后两者有实际优化作用. 可见性: 线程本身并不直接与主内存进行数据的交互,而是通过线程的工作内存来完成相应的操作.

Java并发编程

synchronized是Java中的关键字,在并发编程中被称为内置锁或者监视器锁.当用它来修饰一个方法或者一个代码块的时候能够保证同一时刻最多只有一个线程执行该段代码. Java的内置锁相当于一种互斥锁,最多只有一个线程能够持有这种锁,故而由这个锁保护的同步代码块会以原子方式执行,多个线程在执行该代码时就不会相互干扰. 但由于被锁保护的同步块代码是以串行形式来访问的,即多个线程以独占的方式访问对象,而这也导致如果被锁保护的同步代码块的作用范围过大,会导致并发不良. 这里有必要简单讲一下内置锁的

6、Java并发编程:volatile关键字解析

Java并发编程:volatile关键字解析 volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以重获生机. volatile关键字虽然从字面上理解起来比较简单,但是要用好不是一件容易的事情.由于volatile关键字是与Java的内存模型有关的,因此在讲述volatile关键之前,我们先来了解一下与内存模型相关的概念和知识,然后分析了volatil

7、Java并发编程:深入剖析ThreadLocal

Java并发编程:深入剖析ThreadLocal 想必很多朋友对ThreadLocal并不陌生,今天我们就来一起探讨下ThreadLocal的使用方法和实现原理.首先,本文先谈一下对ThreadLocal的理解,然后根据ThreadLocal类的源码分析了其实现原理和使用需要注意的地方,最后给出了两个应用场景. 以下是本文目录大纲: 一.对ThreadLocal的理解 二.深入解析ThreadLocal类 三.ThreadLocal的应用场景 若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者

java并发编程实战学习(3)--基础构建模块

转自:java并发编程实战 5.3阻塞队列和生产者-消费者模式 BlockingQueue阻塞队列提供可阻塞的put和take方法,以及支持定时的offer和poll方法.如果队列已经满了,那么put方法将阻塞直到空间可用:如果队列为空,那么take方法将阻塞直到有元素可用.队列可以是有界的也可以是无界的. 如果生产者生成工作的速率比消费者处理工作的速率款,那么工作项会在队列中累计起来,最终好紧内存.同样,put方法的阻塞特性也极大地简化了生产者的编码.如果使用有界队列,当队列充满时,生产者将阻

Java 并发编程之任务取消(九)

Jvm关闭 jvm可正常关闭也可强行关闭,正常关闭有多种触发方式: 当最后一个正常(非守护,下面会讲到什么是守护线程)线程结束时 当调用system.exit时,或者通过其他特定于平台的方法关闭时(例如发送了SIGINT信号或键入Ctrl-c) 通过其他特定平台的方法关闭jvm,调用Runtime.halt或者在操作系统当中杀死JVM进程(例如发送sigkill)来强行关闭jvm. 关闭钩子 在正常关闭中,jvm首先调用所有已注册的关闭钩子,关闭钩子是指通过 Runtime.addShutdow

Java并发编程笔记 并发概览

并发概览 >>同步 如何同步多个线程对共享资源的访问是多线程编程中最基本的问题之一.当多个线程并发访问共享数据时会出现数据处于计算中间状态或者不一致的问题,从而影响到程序的正确运行.我们通常把这种情况叫做竞争条件(race condition),把并发访问共享数据的代码叫做关键区域(critical section).同步就是使得多个线程顺序进入关键区域从而避免竞争条件的发生. >>线程安全性 编写线程安全的代码的核心是要对状态访问操作进行管理,尤其是对共享的和可变的状态访问. 线