使用Java实现单线程模式
我们都知道单例模式,有很多种实现方法。今天我们实现一个单线程实例模式,也就是说只能实例化该类的一个线程来运行,不允许有该类的多个线程实例存在。直接上代码:
- public class SingletonThread implements Runnable
- {
- /** 获取access_token 和 expire_in 的url */
- private static final String accessTokenUrl =
"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="- + ParameterConfig.WX_APPID + "&secret=" + ParameterConfig.WX_APPSECRET;
- /** 这里使用public volatile发布一个共享对象 */
- private static volatile AccessToken accessToken; // 因为是一个线程写多个线程读,而引用的又是“不可变对象”,
// 所以使用volatile保证“可见性”- // 保证无法实例化 SingletonThread
- private SingletonThread(){}
- // 静态类保证thread的初始化是线程安全的,内部类实现了延迟加载的效果
- private static class SingletonThreadHolder
- {
- public static SingletonThread thread = new SingletonThread();
- }
- public static SingletonThread getInstance()
- {
- return SingletonThreadHolder.thread;
- }
- @Override
- public void run()
- {
- while(true)
- {
- try{
- HttpsURLConnection conn = HttpUtil.initHttpsConnection(accessTokenUrl, "GET");
- String result = HttpUtil.getHttpsContent(conn, "utf-8");
- JSONObject json = null;
- if(result != null)
- json = JSON.parseObject(result);
- if(json != null){
- accessToken = new AccessToken(json.getString("access_token"), json.getLong("expires_in"));
- }else{
- System.out.println("get access_token failed----");
- }
- }catch(IOException e){
- e.printStackTrace();
- }
- try{
- if(null != accessToken){
- Thread.sleep((accessToken.getExpire_in() - 200) * 1000); // 休眠7000秒
- }else{
- Thread.sleep(60 * 1000); // 如果access_token为null,60秒后再获取
- }
- }catch(InterruptedException e){
- try{
- Thread.sleep(60 * 1000);
- }catch(InterruptedException e1){
- e1.printStackTrace();
- }
- }
- }
- }
public static AccessToken getAccessToken() {
return accessToken;
}- }
也可以扩展Thread类来实现:
- public class SingletonThread2 extends Thread
- {
- /** 获取access_token 和 expire_in 的url */
- private static final String accessTokenUrl =
"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="- + ParameterConfig.WX_APPID + "&secret=" + ParameterConfig.WX_APPSECRET;
- // 这里使用public发布一个共享对象
- private static volatile AccessToken accessToken; // 因为是一个线程写多个线程读,而引用的又是“不可变对象”,
// 所以使用volatile保证“可见性”- // 保证无法实例化 SingletonThread
- private SingletonThread2(){}
- // 静态类保证thread的初始化是线程安全的,内部类实现了延迟加载的效果
- private static class SingletonThreadHolder
- {
- public static SingletonThread2 thread = new SingletonThread2();
- }
- public static SingletonThread2 getInstance()
- {
- return SingletonThreadHolder.thread;
- }
- @Override
- public void run()
- {
- while(true)
- {
- try{
- HttpsURLConnection conn = HttpUtil.initHttpsConnection(accessTokenUrl, "GET");
- String result = HttpUtil.getHttpsContent(conn, "utf-8");
- JSONObject json = null;
- if(result != null)
- json = JSON.parseObject(result);
- if(json != null){
- accessToken = new AccessToken(json.getString("access_token"), json.getLong("expires_in"));
- }else{
- System.out.println("get access_token failed----");
- }
- }catch(IOException e){
- e.printStackTrace();
- }
- try{
- if(null != accessToken){
- Thread.sleep((accessToken.getExpire_in() - 200) * 1000); // 休眠7000秒
- }else{
- Thread.sleep(60 * 1000); // 如果access_token为null,60秒后再获取
- }
- }catch(InterruptedException e){
- try{
- Thread.sleep(60 * 1000);
- }catch(InterruptedException e1){
- e1.printStackTrace();
- }
- }
- }
- }
public static AccessToken getAccessToken() {
return accessToken;
}- }
这里的场景是:微信开发中需要每隔2个小时从腾讯的微信服务器刷新access_token,所以这里只需要使用单个线程无线循环每隔2小时刷新一次即可,我们不希望出现该类的多个线程,每个线程都去刷新access_token。
注意如果在一个线程上调用多次 start() 方法是会抛出 IllegalThreadStateException 异常的。
这里的实现其实也来自于单实例模式的一种写法,实现了线程安全和延迟加载的效果。其实对应于单例模式,单线程模式也有多种实现方法,比如使用 静态属性:
- public class SingletonThread3 extends Thread
- {
- private static SingletonThread3 thread = new SingletonThread3(); // static保证线程安全
- // 保证无法实例化 SingletonThread
- private SingletonThread3(){}
- public static SingletonThread3 getInstance()
- {
- return thread;
- }
- @Override
- public void run()
- {
- // ...
- }
- }
这种实现也是线程安全的,但是没有延迟加载的效果。
AccessToken是一个“不可变对象”的类:
- /**
- * access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。
- * 开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。
- * access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
- * 目前access_token的有效期通过返回的expire_in来传达,目前是7200秒之内的值
- * @author digdeep@126.com
- * 这是一个“不可变”对象的类定义
- */
- public class AccessToken
- {
- private final String access_token;
- private final long expire_in; // access_token有效时间,单位为妙
- public AccessToken(String access_token, long expire_in)
- {
- this.access_token = access_token;
- this.expire_in = expire_in;
- }
- public String getAccess_token() {
- return access_token;
- }
- public long getExpire_in() {
- return expire_in;
- }
- }
其实几乎可以将每一种单实例模式都可以改造成一种单线程模式,改造方法就是让其 implements Runnable 或者 extends Thread 重写run()方法即可,因此不再举例...
很显然 单线程模式 适应的场景为:一个始终运行(死循环)的单个线程,比如一个永不停止的单个后台线程,在后台实现一些辅助功能,或者实现垃圾回收之类的功能。有不允许多个线程执行的要求。比如本文中的刷新微信的access_token,就没有必要用多个线程不断的去刷新了,而且这样会造成混乱,不知道那个线程获得的access_token才是正确的(因为后一个线程获得的access_token会覆盖前一个的)。
使用Java实现单线程模式的更多相关文章
- JAVA NIO non-blocking模式实现高并发服务器(转)
原文链接:JAVA NIO non-blocking模式实现高并发服务器 Java自1.4以后,加入了新IO特性,NIO. 号称new IO. NIO带来了non-blocking特性. 这篇文章主要 ...
- 基于Java 生产者消费者模式(详细分析)
Java 生产者消费者模式详细分析 本文目录:1.等待.唤醒机制的原理2.Lock和Condition3.单生产者单消费者模式4.使用Lock和Condition实现单生产单消费模式5.多生产多消费模 ...
- JAVA NIO non-blocking模式实现高并发服务器
JAVA NIO non-blocking模式实现高并发服务器 分类: JAVA NIO2014-04-14 11:12 1912人阅读 评论(0) 收藏 举报 目录(?)[+] Java自1.4以后 ...
- Java设计模式——组合模式
JAVA 设计模式 组合模式 用途 组合模式 (Component) 将对象组合成树形结构以表示“部分-整体”的层次结构.组合模式使得用户对单个对象和组合对象的使用具有唯一性. 组合模式是一种结构型模 ...
- java装饰者模式理解
java 装饰者模式其实就是扩展子类的功能,和继承是一个性质. 但继承是在编译时就固定扩展了父类的一些功能,而装饰者模式是在运行过程中动态绑定对象,实现一个子类可以随时扩展功能. 将方法排列组合,也可 ...
- !!转!!java 简单工厂模式
举两个例子以快速明白Java中的简单工厂模式: 女娲抟土造人话说:“天地开辟,未有人民,女娲抟土为人.”女娲需要用土造出一个个的人,但在女娲造出人之前,人的概念只存在于女娲的思想里面.女娲造人,这就是 ...
- java 双重检查模式
java 双重检查模式 在并发环境下 兼顾安全和效率 成例(Idiom)是一种代码层次上的模式,是在比设计模式的层次更具体的层次上的代码技巧.成例往往与编程语言密切相关.双重检查成例(Double C ...
- Java 抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是工厂方法模式的进一步抽象,其英文原话"Provide an interface for creating families ...
- Java之模板方法模式(Template Method)
Java之模板方法模式(Template Method) 1. 概念:定义一个算法的骨架,而将一些实现步骤延迟到子类中. 把不变的行为搬到超类,去除子类中重复的代码来体现他的优势. 2. UML图: ...
随机推荐
- The type java.lang.CharSequence cannot be resolved. It is indirectly referenced from required .class files.
参照 http://stackoverflow.com/questions/24301986/the-type-java-lang-charsequence-cannot-be-resolved-in ...
- (实例篇)PHP实现HTTP断点续传的方法
PHP实现HTTP断点续传的方法. <?php /** * PHP-HTTP断点续传实现 * @param string $path: 文件所在路径 * @param string $file: ...
- 异步与并行~List<T>是线程安全的吗?
返回目录 题目有点意思,大家都知道Dictionary<K,V>不是线程安全的类型,而List<T>是线程安全的吗?在今天之前大叔没有去测试过,而就在今天也是一个VIP问我,说 ...
- iOS中数据库应用基础
iOS 数据库入门 一.数据库简介 1.什么是数据库? 数据库(Database) 是按照数据结构来组织,存储和管理数据的仓库 数据库可以分为2大种类 关系型数据库(主流) PC端 Oracle My ...
- 《JS设计模式笔记》 5,适配器模式
//适配器模式的作用就像一个转接口. jQuery("#"+id); $id=function (id) { return jQuery("#"+id)[0]; ...
- 创建 Monitor 并测试 - 每天5分钟玩转 OpenStack(124)
前面我们创建了 Pool,VIP 并添加了 Member.今天将创建 Monitor,然后测试 LBaaS 是否能够正常工作. 创建 Monitor LBaaS 可以创建 monitor,用于监控 P ...
- JMS学习之路(一):整合activeMQ到SpringMVC
JMS的全称是Java Message Service,即Java消息服务.它主要用于在生产者和消费者之间进行消息传递,生产者负责产生消息,而消费者负责接收消息.把它应用到实际的业务需求中的话我们可以 ...
- 读书笔记--SQL必知必会09--汇总数据
9.1 聚集函数 聚集函数(aggregate function),对某些行运行的函数,计算并返回一个值. 使用聚集函数可以汇总数据而不必将涉及的数据实际检索出来. 可利用标准的算术操作符,实现更高级 ...
- [入门级] visual studio 2010 mvc4开发,用ibatis作为数据库访问媒介(一)
[入门级] visual studio 2010 mvc4开发,用ibatis作为数据库访问媒介(一) Date 周二 06 一月 2015 By 钟谢伟 Tags mvc4 / asp.net 示 ...
- .net两个对象比较,抛出不一样字段的结果
现在应该经常用到记录操作日志,修改和新增必定涉及到两个实体的属性值的变动. 利用反射,将变动记录下来. 切记,类中的属性字段上面需要打上Description标签: 例如: /// <summa ...