使用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图: ...
随机推荐
- Gulp探究折腾之路(I)
前言: gulp是前端开发过程中对代码进行构建的工具,是自动化项目的构建利器:她不仅能对网站资源进行优化,而且在开发过程中很多重复的任务能够使用正确的工具自动完成:使用她,我们不仅可以很愉快的编写代码 ...
- Atitit 图像处理 调用opencv 通过java api attilax总结
Atitit 图像处理 调用opencv 通过java api attilax总结 1.1. Opencv java api的支持 opencv2.4.2 就有了对java api的支持1 1. ...
- C#学习总结之集合
一.集合接口和类型 命名空间: 集合类型 命名空间 一般集合 System.Collections 泛型集合 System.Collections.Generic 特定类型集合 Syst ...
- 5.如何使主机和虚拟机IP处于同一网段(内网渗透专用)
先说一下正常流程: 1.打开虚拟机网络设置选项,选择桥接模式(Bridged)[如果是Kali 2.0的话,执行第一步后就OK了(90%)] 2.打开Kali里面的网络设置 3.设置一个ip4或者ip ...
- Bootstrap3插件系列:bootstrap-select2
1.下载插件 https://github.com/select2/select2 http://select2.github.io/ 2.引用插件 <script src="~/Sc ...
- 【Win10 应用开发】实现数据的增量加载
今天,老周有小故事讲,国庆期间.有一次老周在某站台上候公交车.老周旁边也站满了人,突然,有一位头发弄得像电线杆的小伙子,不知为何,没有先兆地就大笑起来. 老周先是看了那小伙子一眼,他手上没有拿什么东西 ...
- 1、Python基础知识
输出print “houkai”,3.0版本后print修改为函数,print(‘houkai’) 数学运算:默认整数整除1/2=0而1.0/2=0.5,可以使用from __future__ imp ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(28)-系统小结
系列目录 我们从第一节搭建框架开始直到二十七节,权限管理已经告一段落,相信很多有跟上来的园友,已经搭配完成了,并能从模块创建授权分配和开发功能了 我没有发布所有源代码,但在14节发布了最后的一次源代码 ...
- GO语言下载、安装、配置
一.Go语言下载 go语言官方下载地址:https://golang.org/dl/ 找到适合你系统的版本下载,本人下载的是windows版本.也可以下载Source自己更深层次研究go语言. 二.G ...
- [Spring]04_最小化Spring XML配置
4.1 自动装配 Bean Spring 装配 bean 时,有时非常明确,就是需要将某个 bean 的引用装配给指定属性. 例如,若应用上下文中只有一个 javax.sql.DataSource 类 ...