在java中,有一些线程安全操作的常识,在这里我进行总结一下:
1、java.util.concurrent.atomic包中包含了一些原子变量类,用于实现在数值和对象引用上的原子状态转换。通过用AtomicLong来代替long类型的计数器,能够确保所有对计数器状态的访问操作都是原子的。
@ThreadSafe
public class Counting{
private final AtomicLong count = new AtomicLong(0);
public long getCount(){
return count.get();
}
//safe method
public yourMathod(){
//do something
count.incrementAndGet();
//do something
}
}
同时合理利用同步代码块的合理大小,需要在各种设计需求中间进行权衡,包括安全性、简单性和性能。注意这里不要和atomic进行混用,因为这样会带来操作和管理上的麻烦。
//@GuardedBy( lock )有以下几种使用形式:
//1、@GuardedBy( "this" ) 受对象内部锁保护
//2、@GuardedBy( "fieldName" ) 受 与fieldName引用相关联的锁 保护。
//3、@GuardedBy( "ClassName.fieldName" ) 受 一个类的静态field的锁 保存。
//4、@GuardedBy( "methodName()" ) 锁对象是 methodName() 方法的返值,受这个锁保护。
//5、@GuardedBy( "ClassName.class" ) 受 ClassName类的直接锁对象保护。而不是这个类的某个实例的锁对象。
@GuardeBy("this") private long counts;
public synchronized long getCounts(){return counts;}
public void yourMethod()
{
synchronized(this){
++counts;
}
}
2、关于可变对象的安全发布,在Java并发实战中,介绍了以下方式安全发布:
- 在静态初始化函数中初始化一个对象引用。
- 将对象的引用保存到volatile类型的域或者AtomicReferance对象中。
- 将对象的引用保存到某个正确构造对象的final类。
- 将对象的引用保存到一个由锁保护的域中。
3、线程安全库中的容器提供的安全发布保证:
- 通过将一个键或者值放入Hashtable、synchronizedMap或者ConcurrentMap中,可以安全地将它发布给任何从这些容器中访问它的线程。
- 通过将某个元素放入Vector、CopyOnWriteArrayList、CopyOnWriteArraySet、synchronizedList或者synchronizedSet中,可以将该元素安全地发布到任何从这些容器中访问该元素的线程。
- 通过将某个元素放入BlockingQueue或者ConcurrentLinkedQueue中,可以将该元素安全地发布到任何从这些队列中访问该元素的线程。
4、使用同一个锁策略
错误方式:
@NotThreadSafe
public class ListHelper<E>{
public List<E> list = Collections.synchronizedList(new ArrayList<E>());
public synchronized boolean putIfAbsent(E x){
boolean absent = !list.contains(x);
if(absent){
list.add(x);
}
return absent;
}
}
正确方式:
@NotThreadSafe
public class ListHelper<E>{
public List<E> list = Collections.synchronizedList(new ArrayList<E>());
public boolean putIfAbsent(E x){
synchronized(list){
boolean absent = !list.contains(x);
if(absent){
list.add(x);
}
return absent;
}
}
}
5、在使用Vector时也会出现由于方法不是原子操作,导致得到的数据异常,这里的解决办法是:
public void yourMethod(){
synchronized(vector){
//do someThing
//vector.get(i);
//vector.put(object);
}
}
6、迭代器对容器的修改由于性能的原因是没有考虑并发的,如果数据过于太大,不希望在迭代期间对容器加锁,那么一种替代方法就是‘克隆’容器,并在副本上进行迭代,但是在克隆的期间,是会考虑加锁并发的。
7、与Hashtable和synchronizedMap相比,ConcurrenctHashMap有着更多的优势以及更少的劣势,因此在大多数并发情况下,用ConcurrentHashMap来代替同步Map能进一步提高代码的可伸缩性。只有当应用程序需要加锁Map以进行独占访问时,才放弃使用ConcurrentHashMap。
8.使用Semaphore为容器设置边界,也可以用BlockingQueue来保存池的资源,当资源没有时,会出现阻塞,直到有用资源的释放。
public class BoundedHashSet<T>{
private final Set<T> set;
private final Semaphore sem;
public BoundedHashSet(int bound){
this.set = Collections.synchronizedSet(new HashSet<T>());
sem = new Semaphore(bound);
}
public boolean add(T o) throws InterruptedException{
sem.acquire();
boolean wasAdded = false;
try{
wasAdded = set.add(o);
return wasAdded;
}
finally{
if(!wasAdded)
sem.release();
}
}
public boolean remove(Object o){
boolean wasRemoved = set.remove(o);
if(wasRemoved){
sem.release();
}
return wasRemoved;
}
}
9.通过CyclicBarrier协调细胞自动衍生系统中的计算,主要用于把一个问题分成几个子问题,并每个问题分配一个子线程,当所有工作线程都完成到达栅栏时,来判断是否需要进行下一次迭代。另外一种形式是Exchanger,他是两方(Two-party)栅栏,一般用于两个缓冲区进行任务判断交换。
public class CellularAutomata{
private final Board mainBoard;
private final CyclicBarrier barrier;
private final Worker[] workers;
public CellularAutomata(Board board){
this.mainBoard = board;
int count = Runtime.getRuntime().availableProcessors();
this.barrier = new CyclicBarrier(count,new Runable(){
public void run(){
mainBoard.commitNewValues();
}
});
this.workers = new Worker[count];
for(int i=0;i<count;i++){
workers[i] = new Worker(mainBoard.getSubBoard(count,i));
}
}
private class Worker implements Runnable{
private final Board board;
public Worker(Board board){this.board = board;}
public void run(){
while(!board.hasConverged()){
for(int x=0;x < board.getMaxX();x++){
for(int y=0;y<board.getMaxY();y++)
board.setNewValue(x,y,computeValue(x,y));
}
try{
barrier.await();
} catch(InterruptedException ex){
return;
} catch(BrokerBarrierException ex){
return;
}
}
}
}
public void start(){
for(int i=0;i<workers.lengthl;i++)
new Thread(workers[i]).start();
mainBoard.waitForConvergence();
}
}
分享到:
相关推荐
Java线程安全是多线程编程中的一个关键概念,它涉及到在并发环境下如何正确地管理共享资源,确保程序的正确性和一致性。以下是对Java线程安全的深入总结: ### 一、线程安全的定义 线程安全是指当多个线程访问同一...
Java线程安全是多线程编程中的一个关键概念,它涉及到多个线程访问共享资源时可能出现的问题。在Java中,线程安全问题通常与并发、内存模型和可见性有关。Java内存模型(JMM)定义了如何在多线程环境下共享数据的...
### JAVA线程安全及性能优化的关键知识点 #### 一、JAVA内存模型与线程安全的基础概念 **JAVA内存模型**是理解线程安全的核心。不同的操作系统平台可能有不同的内存管理方式,但Java虚拟机(JVM)提供了一套统一的...
其实java的多线程并发问题最终都会反映在java的内存模型上,所谓线程安全无非是要控制多个线程对某个资源的有序访问或修改。总结java的内存模型,要解决两个主要的问题:可见性和有序性。我们都知道计算机有高速缓存...
"Java线程安全" Java线程安全是指在多线程并发编程中,如何确保线程安全地访问和修改共享资源的问题。Java内存模型(JMM)是Java虚拟机(JVM)定义的内存模型,旨在屏蔽底层平台的内存管理细节,提供了一个统一的...
### Java线程安全的核心概念与实践 #### 一、Java内存模型 理解Java线程安全首先需要掌握Java内存模型(JMM)。JMM是Java虚拟机(JVM)的一部分,它规定了程序中各种变量(包括实例字段、静态字段和构成数组对象的...
Java线程安全与生产者消费者模型是多线程编程中的两个重要概念,它们在并发处理中扮演着关键角色。在Java中,线程安全是指一个类或者方法在多线程环境下能够正确地处理数据,避免数据的不一致性或竞态条件。而生产者...
Java线程安全是多线程编程中的一个核心概念,尤其在服务器端开发中,理解并掌握线程安全至关重要。线程安全是指当多个线程访问一个对象时,如果这个对象的状态始终保持一致,那么我们就说这个对象是线程安全的。在...
标题“java线程安全总结.pdf”指向了文档的主要内容:这是关于Java编程语言中的线程安全问题的总结性资料。线程安全是并发编程中的一个核心概念,它与Java多线程技术紧密相关。文档的描述信息非常简洁,只是重复了...
Java线程安全主要涉及到的是多线程环境下对共享资源的管理和控制,以确保并发执行的线程能正确地访问和修改数据,避免出现数据不一致或者竞态条件等问题。Java内存模型(JMM)是Java虚拟机规范的一部分,它定义了...
Java线程安全与锁是多线程编程中的关键概念,主要涉及到并发环境下对共享资源的访问控制。在Java中,线程安全问题主要是由于多个线程同时访问并修改同一份数据,导致数据不一致或者出现意外的行为。为了解决这个问题...
用思维导图将Java线程安全性相关基本概念联系起来
Java线程安全是多线程编程中的一个核心概念,它涉及到在并发环境下如何正确地管理共享资源,确保程序的正确性和一致性。Java提供了一系列机制来处理线程安全问题,包括同步机制、线程局部变量、并发集合等。下面将...
Java线程安全主要涉及到的是在多线程环境下如何正确地管理和操作共享资源,以确保程序的正确性和一致性。Java内存模型(JMM)是解决这一问题的关键,它为多线程编程提供了一套规范,旨在解决可见性和有序性这两个...
Java线程安全性是多线程编程中的核心概念,关乎程序的稳定性和正确性。Java提供了多种机制来确保线程安全,主要包括原子性、可见性和有序性。 **原子性**是线程安全的基础,保证了操作不会被其他线程打断。Java提供...
总之,"java线程安全-往盘子里放鸡蛋和向盘子里取鸡蛋"是一个典型的并发编程问题,通过合理使用Java提供的同步机制,我们可以确保在多线程环境下正确地管理和操作共享资源,避免数据不一致性和竞态条件等问题。...