实现Java线程安全
一个类如果想要满足线程安全的条件:
- 每个线程都能正常的执行原子操作,保证得到正确的结果
- 这个类的对象可以同时被多个线程安全的访问
- 在每个线程的原子操作都完成后,对象处于合理的状态
一般情况下不可变类总是线程安全的,因为他的对象的状态始终不会改变,任何线程只能读取他的状态,而不能改变他的状态,例如String类就是一个不可变类,因为String类在我们的代码中使用的实在是太多了,如果设计成可变类后果可想而知……对于那些可变类,如果想要保证它的们的线程安全,就要保证对于他们的原子操作进行同步。
我们常说StirngBuffer是线程安全的,StringBuilder是线程不安全的,为什么呢?因为在StringBuffer类中大量使用了同步,以下只是一小部分方法,方法都用synchronized关键字修饰,做到同步
但是大量运用同步可能对性能造成影响,同步的意思好比大家一起排队做某件事,举个例子i,有十个人去吃饭,但是饭店的座位只有一个,只能一个一个吃,第一个人先吃,这样依次下去,那么第十个人要等到前面九个人都吃完了才能吃饭,想想是不是很委屈。对可变类实现同步往往都会降低并发性能,为了减少带来的影响,我们可以采取下面的措施:
- 只对额能导致资源竞争的代码进行同步处理,对于那些没有资源竞争的代码不进行处理,例如我们在对一个属性提供set和get方法的时候,试着只提供get方法获取值,不提供set方法修改值,这样虽然好多个线程同时访问,也不会造成数据的错误和资源的竞争。
- 对于多线程环境下我们提供一个运行方式,对于单线程环境下提供一个运行方式。一个类提供两种实现方式,在单线程运行环境下采用微进行同步实现的代码,对于对线程运行环境下采用进行同步处理的代码,避免一刀切。这里有个很好的例子,Map,Set,List这三个集合类都是线程不安全的,在多线程环境下怎么办呢?Collections类提供了很好的解决办法,他提供了返回这些集合同步版本的静态内部类,并在类中重写了集合中所有有资源竞争的方法,加了synchronized关键字进行同步处理
SynchronizedCollection和三个集合一样,也是实现了同步的方法,看代码:
public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<>(list) :
new SynchronizedList<>(list));
}
static <T> List<T> synchronizedList(List<T> list, Object mutex) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<>(list, mutex) :
new SynchronizedList<>(list, mutex));
}
/**
* @serial include
*/
static class SynchronizedList<E>
extends SynchronizedCollection<E>
implements List<E> {
private static final long serialVersionUID = -7754090372962971524L;
final List<E> list;
SynchronizedList(List<E> list) {
super(list);
this.list = list;
}
SynchronizedList(List<E> list, Object mutex) {
super(list, mutex);
this.list = list;
}
public boolean equals(Object o) {
if (this == o)
return true;
synchronized (mutex) {return list.equals(o);}
}
public int hashCode() {
synchronized (mutex) {return list.hashCode();}
}
public E get(int index) {
synchronized (mutex) {return list.get(index);}
}
public E set(int index, E element) {
synchronized (mutex) {return list.set(index, element);}
}
public void add(int index, E element) {
synchronized (mutex) {list.add(index, element);}
}
public E remove(int index) {
synchronized (mutex) {return list.remove(index);}
}
public int indexOf(Object o) {
synchronized (mutex) {return list.indexOf(o);}
}
public int lastIndexOf(Object o) {
synchronized (mutex) {return list.lastIndexOf(o);}
}
public boolean addAll(int index, Collection<? extends E> c) {
synchronized (mutex) {return list.addAll(index, c);}
}
public ListIterator<E> listIterator() {
return list.listIterator(); // Must be manually synched by user
}
public ListIterator<E> listIterator(int index) {
return list.listIterator(index); // Must be manually synched by user
}
public List<E> subList(int fromIndex, int toIndex) {
synchronized (mutex) {
return new SynchronizedList<>(list.subList(fromIndex, toIndex),
mutex);
}
}
public static <T> Set<T> synchronizedSet(Set<T> s) {
return new SynchronizedSet<>(s);
}
static <T> Set<T> synchronizedSet(Set<T> s, Object mutex) {
return new SynchronizedSet<>(s, mutex);
}
/**
* @serial include
*/
static class SynchronizedSet<E>
extends SynchronizedCollection<E>
implements Set<E> {
private static final long serialVersionUID = 487447009682186044L;
SynchronizedSet(Set<E> s) {
super(s);
}
SynchronizedSet(Set<E> s, Object mutex) {
super(s, mutex);
}
public boolean equals(Object o) {
if (this == o)
return true;
synchronized (mutex) {return c.equals(o);}
}
public int hashCode() {
synchronized (mutex) {return c.hashCode();}
}
}
我们可以通过代码看到他是实现了一个静态方法,在静态方法中去创建这个静态类,而这个静态类重写了集合中有资源竞争关系的方法(加了同步处理)
参考:Java面向对象编程--孙卫琴
实现Java线程安全的更多相关文章
- Java线程并发:知识点
Java线程并发:知识点 发布:一个对象是使它能够被当前范围之外的代码所引用: 常见形式:将对象的的引用存储到公共静态域:非私有方法中返回引用:发布内部类实例,包含引用. 逃逸:在对象尚未准备 ...
- Java线程的概念
1. 计算机系统 使用高速缓存来作为内存与处理器之间的缓冲,将运算需要用到的数据复制到缓存中,让计算能快速进行:当运算结束后再从缓存同步回内存之中,这样处理器就无需等待缓慢的内存读写了. 缓 ...
- Java 线程池框架核心代码分析--转
原文地址:http://www.codeceo.com/article/java-thread-pool-kernal.html 前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和 ...
- 细说进程五种状态的生老病死——双胞胎兄弟Java线程
java线程的五种状态其实要真正高清,只需要明白计算机操作系统中进程的知识,原理都是相同的. 系统根据PCB结构中的状态值控制进程. 单CPU系统中,任一时刻处于执行状态的进程只有一个. 进程的五种状 ...
- 【转载】 Java线程面试题 Top 50
Java线程面试题 Top 50 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题.Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员 的欢迎.大多数待遇丰厚的J ...
- 第24章 java线程(3)-线程的生命周期
java线程(3)-线程的生命周期 1.两种生命周期流转图 ** 生命周期:**一个事物冲从出生的那一刻开始到最终死亡中间的过程 在事物的漫长的生命周期过程中,总会经历不同的状态(婴儿状态/青少年状态 ...
- 第23章 java线程通信——生产者/消费者模型案例
第23章 java线程通信--生产者/消费者模型案例 1.案例: package com.rocco; /** * 生产者消费者问题,涉及到几个类 * 第一,这个问题本身就是一个类,即主类 * 第二, ...
- 第22章 java线程(2)-线程同步
java线程(2)-线程同步 本节主要是在前面吃苹果的基础上发现问题,然后提出三种解决方式 1.线程不安全问题 什么叫线程不安全呢 即当多线程并发访问同一个资源对象的时候,可能出现不安全的问题 对于前 ...
- 第21章 java线程(1)-线程初步
java线程(1)-线程初步 1.并行和并发 并行和并发是即相似又有区别: 并行:指两个或者多个事件在同一时刻点发生. 并发:指两个或多个事件在同一时间段内发生 在操作系统中,并发性是指在一段事件内宏 ...
- [转]Java线程安全总结
最近想将java基础的一些东西都整理整理,写下来,这是对知识的总结,也是一种乐趣.已经拟好了提纲,大概分为这几个主题: java线程安全,java垃圾收集,java并发包详细介绍,java profi ...
随机推荐
- [javascript]一段焦点图的js代码
<html> <head> <meta name="name" content="content"charset="ut ...
- C#连接oracle数据库步骤
1. 确认操作系统类型,操作系统是64位还是32位: 2. 按对应版本安装oralce客户端版本(64位还是32位): 3. 安装oralce管理员模块,同时赋予安装目录权限 4. 注册old ...
- Angular21 动态绑定CSS样式
1 需求 在前端开发中通常需要动态对某些元素的样式进行动态设定,传统的CSS绑定分为CSS类绑定和Style样式绑定:在Angular中利用相关指令同样可以完成CSS类绑定和CSS样式绑定 2 内置指 ...
- ACM1007
题目:DNA序列排序 DNA序列由一序列的大写英文字母表示,如ABCDEF.紊乱程度表示组成DNA序列的字母按照由小到大的顺序进行排列程度,如ABC的紊乱程度比ACB小,因为它字母都是由小到大排序的. ...
- ASP.NET WebForm 通过 PagedDataSource 实现 Repeater 的分页
1.效果图&代码说明 1.效果图 2.代码说明 1.翻页按钮 前台两个LinkButton(上一页.下一页),设置不同的CommandName.CommandArg ...
- Python基础__函数
本节将进入函数的介绍,函数是Python基础中最精彩的部分之一,接下来将对函数做详细介绍.函数 函数就是对代码进行一个封装.把实现某一功能的代码进行封装到一起.下次需要使用时不需要进行编写代码直接调用 ...
- NOIWC2018游记
NOIWC2018游记 接着PKUWC就是NOIWC了.感觉时间很紧呀,但越是紧张呢,就越让人心里觉得充实. 能够去NOIWC,应该是一次非常充实的体验吧. 这一篇游记是接着上一篇写的,时间点上完全都 ...
- oracle数据库和表的操作
一.字符函数 (1)连接符 concat --连接符 select concat('10086','-')||'1531234567' 电话号 from dual; (2)首字母大写 initcap ...
- CodeFirst学习笔记
一.概要 本文主要是学习CodeFirst思想.技术上的实现是C#(.net framework4.6.1) 控制台 + PostgreSQL 10.2.1 代码:https://pan.baidu. ...
- 【learning】莫比乌斯反演
吐槽 额其实这个东西的话..好像缠着机房里面的dalao们给我讲过好多遍了然后.. 拖到现在才搞懂也是服了qwq(可能有个猪脑子) 感觉就是主要几条式子然后疯狂换元换着换着就化简运算了? 草稿纸杀手q ...