跟着实例学习java多线程7-对象的组合发布

我们学习线程安全与同步的知识目的就是要实现一些可复用组件或编写出更大的程序。

java中类是对象抽象,那么怎么实现一个线程安全类是我们必须要知道的并正确使用的技术。

在设计线程安全类的过程中,需要包含以下三个基本元素:

找出构成对象状态的所有变量。

找出约束状态变量的不变性条件。

建立对象状态的并发访问管理策略。

package com.home.thread.thread7;

import com.home.thread.safe;

public class Counter {

	/**
	 * @author gaoxu
	 *
	 */
	public class SafeThread {
		private int id = 0;

		@safe
		public synchronized int getId(){

				if(id==Integer.MAX_VALUE)
					throw new IllegalStateException("counter overflow");
				return ++id;

		}

	}
}

方法getId被原子化,这里主要是因为id的状态判断是一个约束条件,而这个约束条件决定了id的值的有效性,所以必须对这步操作做原子化处理。

实例封闭

我们在编写程序中多数会使用一些非线程安全的对象来实现数据的存储,这样的对象如果被多线程访问或是写入,那么就必须做线程安全处理,最好的方式是线程中的封闭处理。让我们来看一个经常会用到的实例:

package com.uskytec.ubc.foundation.queue;

import java.util.LinkedList;

import com.uskytec.ubc.foundation.entity.SmsSubmitEntity;

/**保存到短信猫的信息的队列
 * @author GaoXu
 *
 */
public class LNSentCache {

	private static LNSentCache instance = null;

	public synchronized static LNSentCache getInstance()
	{
		if (instance == null)
			instance = new LNSentCache();
		return instance;
	}
	private final static LinkedList<SmsSubmitEntity> routeCache = new LinkedList<SmsSubmitEntity>();

	/**
	 * 添加到指定缓冲池
	 * @param type
	 * @param smgpConfigID
	 * @param submitMsg
	 * @return
	 */
	public synchronized int add(SmsSubmitEntity sms)
	{

		routeCache.add(sms);
		return 1;
	}

	/**
	 * 得到指定缓冲池的的对象
	 * @param sgipConfigID
	 * @return
	 */
	public synchronized Object get()
	{

		    if (routeCache != null&&routeCache.size()>0)
			    return routeCache.removeFirst();
		    return null;
	}

}

我们利用LinkedList来实现一个先进先出队列,但是LinkedList不是线程安全的,所以我们把它进行实例封闭,这样任何一个线程都可以访问它的值。

线程安全性委托

我们经常会使用ConcurrentHashMap这样的并发对象,它们是java提供的并发变成对象,它们在内部实现了同步机制,所以它们是线程安全的,我们可以把不安全对象Map的访问完全交给它来委托管理,这样通过final类型的处理,我们只需要通过Collections的浅拷贝实现Map的线程安全。

实例我们先不提供,大家可以回去试着写一下,下一节我们在来讨论。

利用现有线程安全的类实现并发添加功能

java api中有很多这样的类,例如:Vector、HashTable等,让我们来看一个例子。

package com.gome.qiantai.tools;

import java.util.Vector;

import com.gome.qiantai.service.IAppraiseWriterObserverService;

/**
 * @author gaoxu
 *
 */
public class ObserverCache {

	private static ObserverCache instance = null;

	public synchronized  static ObserverCache getInstance()
	{
		if (instance == null)
			instance = new ObserverCache();
		return instance;
	}

	private static Vector<IAppraiseWriterObserverService> obs = new Vector<IAppraiseWriterObserverService>();

	public Vector<IAppraiseWriterObserverService> getObs(){

		return obs;
	}

}

我们利用Vector来实现了一个监听器列表的操作。

同步类是我们在实践中经常要实现的类,我们要多思考这样的问题,我的类需要写成线程安全的吗?

时间: 2024-11-08 23:19:27

跟着实例学习java多线程7-对象的组合发布的相关文章

跟着实例学习java多线程-2

上一篇文章我们通过一个实例来说明了并发编程为什么要做同步处理,下面我们再来巩固一下. 对象如果拥有可变状态的变量,并且被多线程访问,那么这个时候我们要对可变状态变量的状态改变做原子操作处理. 锁机制是保证这样的操作的一个有效的方法,它可以保证变量的状态在被更新时是在一个原子操作中进行的. java提供了一种内置锁机制来支持原子性:同步代码块(Synchronized Block). 同步代码块包括两个部分:一个是作为锁的对象引用,一个是作为由这个锁保护的代码块. 让我们在来回忆上一篇文章最后的问

跟着实例学习java多线程6-如何正确发布线程安全的对象

我们前面所讲的一切其实都只是为了一个目标那就是能正确发布一个线程安全的对象. 一:线程封闭 这个很好理解如果一个变量是在一个线程中完成的状态改变,那么这个变量肯定是线程安全的. 我们常使用的是栈封闭和ThreadLocal类. 在java运行时内存区中有一个虚拟机栈,栈封闭说的就是这个栈,这个栈是线程私有的,它的生命周期与线程相同.虚拟机栈描述描述的是java方法执行的内存模型:每个方法被执行的时候会同时创建一个栈帧用于存储局部变量.操作数栈等.每一个方法被调用直至执行完成的过程,就对应着一个栈

跟着实例学习java多线程8-同步容器类的问题

我们知道java有很多线程安全的容器类,我们也知道如果把可变状态的管理交给这些线程安全类来管理就可以实现线程安全,但是我们还可能遇到不可想象的问题. 例如: package com.home.thread.thread8; import java.util.Vector; /** * @author gaoxu * 实践出真知! */ public class VectorQueue { private static VectorQueue instance; private static Ve

跟着实例学习java多线程-3

同步代码块是一种有效实现操作原子性的方法,上一章我们讲了一些同步的原子操作的基础. 现在我们回忆一下上一章的两个问题. 1:不同的synchronized的写法有什么区别,又该怎么写创建线程的代码呢? 以class实例对象作为锁的写法 写法1 package com.home.thread; /** * @author gaoxu * */ public class SafeThread { @safe public void testPrint(){ synchronized(SafeThre

跟着实例学习java多线程5-初识volatile变量

同步机制可以保证原子操作和内存可见性,但是同步机制对变量的访问性能是我们不得不考虑的问题,java语言提供了一种弱同步机制,volatile变量. 它的原理大致是这样的,当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将变量上的操作与其他内存操作一起重排序.volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量总会返回最新写入的值.(参考<java并发编程实践>一书) 让我们来看一个实例: package

跟着实例学习java多线程9-定时任务实例

定时任务是我们经常遇到的业务场景,我们有很多的功能都需要这样的技术来实现,例如:定时获取一些数据push出去,定时处理一些清理任务,定时检查某个值等.那么我们该怎么实现,在实现中又该注意一些什么? 定时任务就是另开一个线程来执行,其实也是并发的一类,大家可能不好理解,说定时不就是到时间执行一下,怎么还会产生并发,这里主要是看两个指标,一是看执行频率,二是看每次执行的时间,如果执行频率高并且执行任务又会很耗时,那么这时候就形成了并发,当然还有一种情况那就是,定时的job中调用其它服务的方法,而正常

跟着实例学习java多线程4-内存可见性

前三篇我们主要说了多线程访问共享可变状态时需要进行正确的同步处理,保证同一时刻只有一个线程访问相同的数据,我们使用synchronized关键字来实现原子性操作. 今天我们在来认识一下同步的另一个重要方面:内存可见性,这个概念其实很好理解,就是保证在同一个时刻,共享可变状态对访问它的线程呈现出自己最新的状态变化. 我们经常遇到的情景是这样的,一个全局变量计数器,一个线程负责更新该数值,另一些线程获取这个值,那么可见性就是获取值的线程,可以获取到更新线程更新的最新的值. 让我们先来看一个例子,在没

Java多线程 同步 对象锁

多线程.同步: https://www.cnblogs.com/GarfieldEr007/p/5746362.html Java对象锁和类锁全面解析(多线程synchronized关键字): http://blog.csdn.net/u013142781/article/details/51697672 Java Object对象中的wait,notify,notifyAll通俗理解 http://blog.csdn.net/vk5176891/article/details/53945677

java多线程下如何调用一个共同的内存单元(调用同一个对象)

1 /* 2 * 关于线程下共享相同的内存单元(包括代码与数据) 3 * ,并利用这些共享单元来实现数据交换,实时通信与必要的同步操作. 4 * 对于Thread(Runnable target)构造方法创建的线程,轮到它来享用CPU资源时. 5 * 目标对象就会自动调用接口中的run()方法 6 * */ 7 8 /* ----------------举例子------------------- */ 9 10 /* 11 * 使用Thread类创建两个模拟猫和狗的线程,猫和狗共享房屋中的一桶