使用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图: ...
随机推荐
- ELK 安装笔记
logstash -noverify -javaagent:E:\svn\other\nn\jrebel6.0.0+crack\jrebel6.0.0-crack\jrebel.jar -Drebel ...
- C#异常处理经验(原则与方法)
本文是异常处理经验性的文章,其实跟C#关系也不大.比较适合刚刚熟悉异常语法,而缺乏实战的读者.当然,经验老练的读者也可指出不足.给予意见.补充说明,一起完善文章,分享更多知识与经验. 1 ...
- Application Request Route实现IIS Server Farms集群负载详解
序言 随着公司业务的发展,后台业务就变的越来越多,然而服务器的故障又像月经一样,时不时的汹涌而至,让我们防不胜防.那么后台的高可用,以及服务器的处理能力就要做一个横向扩展的方案,以使后台业务持续的稳定 ...
- Redis数据结构详解之List(二)
序言 思来想去感觉redis中的list没什么好写的,如果单写几个命令的操作过于乏味,所以本篇最后我会根据redis中list数据类型的特殊属性,同时对比成熟的消息队列产品rabbitmq,使用red ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(53)-工作流设计-我的批阅
系列目录 前言:由于工作原因工作流一直没时间更新,虽然没有更新,但是批阅和申请差不多,改变一下数据的状态字段就行,有几个园友已经率先完成了 说句实话,一个工作流用文章表达很难,我起初以为这是一个很简单 ...
- 设计模式(六):控制台中的“命令模式”(Command Pattern)
今天的博客中就来系统的整理一下“命令模式”.说到命令模式,我就想起了控制台(Console)中的命令.无论是Windows操作系统(cmd.exe)还是Linux操作系统(命令行式shell(Comm ...
- 安卓Design包之AppBar和Toolbar的联用
前面讲了Design包的的CoordinatorLayout和SnackBar的混用,现在继续理解Design包的AppBar; AppBarLayout跟它的名字一样,把容器类的组件全部作为AppB ...
- RFC4035笔记
章 节 标题 说明 补充说明 支持级别 1 介绍 1.定义DNSSEC协议修改点2.定义以下概念:已签名域(signed zone)和域签名的要求列表3.描述权威域名服务器为了处理签名域的行为变化4. ...
- 从架构层面谈web加载优化(个人整理)
最近听了阿里一位大牛的讲座,讲web架构优化对网页加载的影响,看完之后对他所讲的一些优化方法进行一些总结和整理,发现收获还是蛮多的,下面多为个人整理和个人见解,希望有说的不对的,能及时指出 1.DNS ...
- js正则表达式校验正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...