码迷,mamicode.com
首页 > 编程语言 > 详细

使用Java实现单线程模式

时间:2015-03-28 17:06:52      阅读:152      评论:0      收藏:0      [点我收藏+]

标签:

我们都知道单例模式,有很多种实现方法。今天我们实现一个单线程实例模式,也就是说只能实例化该类的一个线程来运行,不允许有该类的多个线程实例存在。直接上代码:

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发布一个共享对象 */
    public 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 token = new AccessToken(json.getString("access_token"), json.getLong("expires_in"));
                    accessToken = token;
                }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();
                }
            }
        }
    }
}

也可以扩展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发布一个共享对象
    public 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 token = new AccessToken(json.getString("access_token"), json.getLong("expires_in"));
                    accessToken = token;
                }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();
                }
            }
        }
    }
}

这里的场景是:微信开发中需要每隔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() 
	{
		// ...
	}
}

这种实现也是线程安全的,但是没有延迟加载的效果。

其实几乎可以将每一种单实例模式都可以改造成一种单线程模式,改造方法就是让其 implements Runnable 或者 extends Thread 重写run()方法即可,因此不再举例...

 

使用Java实现单线程模式

标签:

原文地址:http://www.cnblogs.com/digdeep/p/4374293.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!