设计线程安全的类 VS 发布线程安全的对象
一、设计线程安全的类
步骤:
找出构成对象状态的所有变量
找出约束状态变量的不变性条件
建立对象状态的并发访问策略
1.在现有的线程安全类中添加功能
(1)重用能减低工作量和提高正确性
(2)如果底层的类改变了同步策略,使用不同的锁来保护它的状态,则子类会被破坏
class BetterVector<E> extends Vector<E>{
public synchronized boolean putIfAbsent(E e){
boolean absent = !contains(e);
if(absent){
add(e);
}
return absent;
}
}
2.客户端加锁机制
(1)对于使用对象X的客户端,如果知道X使用的是什么锁,则使用X本身用于保护其状态的锁,来保护这段客户端代码
(2)同样会破坏同步策略的封装
A.错误示例:
class ListHelper<E>{
public List<E> list = Collections.synchronizedList(new ArrayList<E>()); public synchronized boolean putIfAbsent(E e){
boolean absent = !list.contains(e);
if(absent){
list.add(e);
}
return absent;
}
}
B.正确示例:
class ListHelper<E>{
public List<E> list = Collections.synchronizedList(new ArrayList<E>()); public boolean putIfAbsent(E e){
synchronized(list){
boolean absent = !list.contains(e);
if(absent){
list.add(e);
}
return absent;
}
}
}
3.组合:推荐方式
class ImprovedList<E> implements List<E>{
private final List<E> list;
public ImprovedList(List<E> list){
this.list = list;
} public synchronized boolean putIfAbsent(E e){
boolean absent = !list.contains(e);
if(absent){
list.add(e);
}
return absent;
} public synchronized boolean add(E e) {
//委托..... }
}
二、发布线程安全的对象
1. 发布对象:使对象能在当前作用域之外的代码中使用。既将对象的引用传递到其他类的变量和方法。
(1)变量的静态初始化
(2)声明为volatile变量 或 AtomicReferance对象
(3)声明为final变量
(4)将变量保存在线程安全的容器中(既保存在一个由锁保护的域中)
2. 成员变量的初始化:
(1)直接初始化
(2)构造函数初始化
3. 不可变对象、可变对象
在Java内存模型中,final域能确保初始化过程的安全性,从而可以不受限制的访问不可变对象,并在共享这些对象时无需同步。
在可变对象基础上构建的不可变类:虽然Set对象是可变的,但Set对象通过ThreeStooges的构造函数后,无法对其修改。
public final class ThreeStooges {
private final Set<String> stooges = new HashSet<String>(); public ThreeStooges(){
stooges.add("A");
stooges.add("B");
stooges.add("C");
} public boolean isStooge(String name){
return stooges.contains(name);
}
}
设计线程安全的类 VS 发布线程安全的对象的更多相关文章
- Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量
Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量 一丶线程的理论知识 什么是线程: 1.线程是一堆指令,是操作系统调度 ...
- Java自学-多线程 线程安全的类
Java常见的线程安全相关的面试题 步骤 1 : HashMap和Hashtable的区别 HashMap和Hashtable都实现了Map接口,都是键值对保存数据的方式 区别1: HashMap可以 ...
- Java线程池 ThreadPoolExecutor类
什么是线程池? java线程池是将大量的线程集中管理的类, 包括对线程的创建, 资源的管理, 线程生命周期的管理. 当系统中存在大量的异步任务的时候就考虑使用java线程池管理所有的线程, 从而减少系 ...
- C# 线程(二):关于线程的相关概念
From : http://kb.cnblogs.com/page/42528/ 什么是进程? 当一个程序开始运行时,它就是一个进程,进程包括运行中的程序和程序所使用到的内存和系统资源. 而一个进程又 ...
- Java并发编程(十)设计线程安全的类
待续... 线程安全的类 之前学了很多线程安全的知识,现在导致了我每次用一个类或者做一个操作我就会去想是不是线程安全的.如果每次都这样的考虑的话就很蛋疼了,这里的思路是,将现有的线程安全组件组合为更大 ...
- Java线程与并发库高级应用-线程范围内共享数据ThreadLocal类
1.线程范围内共享变量 1.1 前奏: 使用一个Map来实现线程范围内共享变量 public class ThreadScopeShareData { static Map<Thread, In ...
- Java 类 ThreadLocal 本地线程变量
前言:工作中将要使用ThreadLocal,先学习总结一波.有不对的地方欢迎评论指出. 定义 ThreadLocal并不是一个Thread,而是Thread的局部变量.这些变量不同于它们的普通对应物, ...
- 【Thread】java线程之对象锁、类锁、线程安全
说明: 1.个人技术也不咋滴.也没在项目中写过线程,以下全是根据自己的理解写的.所以,仅供参考及希望指出不同的观点. 2.其实想把代码的github贴出来,但还是推荐在初学的您多亲自写一下,就没贴出来 ...
- java线程并发工具类
本次内容主要讲Fork-Join.CountDownLatch.CyclicBarrier以及Callable.Future和FutureTask,最后再手写一个自己的FutureTask,绝对干货满 ...
随机推荐
- C# 匿名类型 分组 求和
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- asp.net mvc 4多级area实现技巧
今天在工作要实现这个多级area.其原因是这个项目需要多级的功能,大的类别里有小的类别,小的类别里有具体的功能项,每一个功能项还有若干动作Action,所以在菜单和mvc工程的结构上都需要有体现多级的 ...
- 转:[windows]DOS批处理添加任务计划
自动创建每周运行一次的计划任务 创建计划任务可用at,schtasks命令,schtasks提供了很多参数 命令schtasks SCHTASKS /Create [/S system [/U use ...
- Atitit.跨语言 文件夹与文件的io操作集合 草案
Atitit.跨语言 文件夹与文件的io操作集合 草案 1. Jdk原生的太难用了..1 2. PS: apache commons-io包,FileUtils有相关的方法,IOUtils一般是拷 ...
- 实现html锚点的两种方式
1,a标签+name属性. 2,使用标签的id属性:
- C语言基础(16)-指针
一.指针的相关概念 1.1 指针变量 指针是一个变量,存放的是一个地址,该地址指向一块内存空间. 例: ; int *p = &a; // 定义一个指针变量p,&符号可以取得一个变量在 ...
- 485. Max Consecutive Ones【easy】
485. Max Consecutive Ones[easy] Given a binary array, find the maximum number of consecutive 1s in t ...
- 基于OAuth2.0的统一身份认证中心设计
1. 引言 公司经历多年发展后,在内部存在多套信息系统,每套信息系统的作用各不相同,每套系统也都拥有自己独立的账号密码权限体系,这时,每个人员都需要记住不同系统的账号密码,人员入职和离职时,人事部门都 ...
- java - day14 - InnerClass
内部类使用 package com.InnerClass; public class Mama { String name; Baby baby; Mama(String name){ this.na ...
- Vue 组件 非父子组件通信
有时候两个组件也需要通信(非父子关系),在简单的场景下,可以使用一个空的vue实例作为中央事件总线: var bus = new Vue(); //触发组件a中的事件 bus.$emit('id-se ...