使用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发布一个共享对象 */
    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()方法即可,因此不再举例...

时间: 2024-08-25 21:10:13

使用Java实现单线程模式的相关文章

JAVA NIO non-blocking模式实现高并发服务器

JAVA NIO non-blocking模式实现高并发服务器 分类: JAVA NIO2014-04-14 11:12 1912人阅读 评论(0) 收藏 举报 目录(?)[+] Java自1.4以后,加入了新IO特性,NIO. 号称new IO. NIO带来了non-blocking特性. 这篇文章主要讲的是如何使用NIO的网络新特性,来构建高性能非阻塞并发服务器. 文章基于个人理解,我也来搞搞NIO.,求指正. 在NIO之前 服务器还是在使用阻塞式的java socket. 以Tomcat最

基于Java 生产者消费者模式(详细分析)

本文目录:1.等待.唤醒机制的原理2.Lock和Condition3.单生产者单消费者模式4.使用Lock和Condition实现单生产单消费模式5.多生产多消费模式(单面包)6.多生产多消费模式 生产者消费者模式是多线程中最为常见的模式:生产者线程(一个或多个)生成面包放进篮子里(集合或数组),同时,消费者线程(一个或多个)从篮子里(集合或数组)取出面包消耗.虽然它们任务不同,但处理的资源是相同的,这体现的是一种线程间通信方式. 本文将先说明单生产者单消费者的情况,之后再说明多生产者多消费者模

Java的MVC模式简介

Java的MVC模式简介 MVC(Model View Control)模型-视图-控制器 首先我们需要知道MVC模式并不是javaweb项目中独有的,MVC是一种软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Controller),即为MVC.它是一种软件设计的典范, 一.MVC与模板概念的理解 MVC本来是存在于Desktop程序中的,M是指数据模型,V是指用户界面,C则是控制器.使用MVC的目的是将M和V的实现代码分离,从而使同一个

Java Web开发模式

一 Java Web开发模式的变迁 1 最初的Java web服务器端编程技术是Servlet,利用Servlet就可以开发出一个Web应用程序. 2 为了解决Servlet缺陷,SUN推出了JSP技术.但是开发人员又走向了另一个极端就是完全放弃了Servlet. 在JSP页面混合使用HTML标记和java代码编写的脚本元素标记来开发Web程序.采用这种方法虽然可以编写JSP页面变得简单,直观,然而,他只适合于业务流程简单,系统规模较小的应用系统. 如果系统较大的话,就会出现两个严重的缺点: 1

Java装饰者模式

Java装饰者模式简介 一.假设有一个Worker接口,它有一个doSomething方法,Plumber和Carpenter都实现了Worker接口,代码及关系如下: 1.Worker.java package decorator; public interface Worker { public void doSomething(); } 2.Plumber.java public class Plumber implements Worker { @Override public void

Java多线程Future模式

Java多线程Future模式有些类似于Ajax的异步请求Future模式的核心在于:去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑 假设服务器的处理某个业务,该业务可以分成AB两个过程,并且AB两个过程之间不需要彼此的返回结果 A过程需要1秒钟,B过程需要2秒钟,主线程其他操作2秒钟按照正常编写,程序大概需要执行5秒如果按照Future模式只需要执行2秒(取其中运行时间最久的线程的运行时间) Future模式的核心实现在于两个方面 1.多线程运行 主线程采用多线的方

java 动态代理模式

一.相关类及其方法:java.lang.reflect.Proxy,Proxy 提供用于创建动态代理类和实例的静态方法.newProxyInstance()返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序(详见api文档) java.lang.reflect.InvocationHandler,InvocationHandler 是代理实例的调用处理程序 实现的接口.invoke()在代理实例上处理方法调用并返回结果.在与方法关联的代理实例上调用方法时,将在调用处理程序

Java 设计模式 -- 复合模式之二

接着上文的鸭鸣例子:Java 设计模式 -- 复合模式之一 上文中,我们的鸭鸣实现了 装饰者模式  适配器模式  工厂模式的结合 现在,又需要进行改动了,上文,是可以统计一群鸭子的叫声,现在需要能够观察个别鸭子的行为 引入观察者模式: 任何想被观察的Quackable都必须实现下面的接口 public interface QuackObservable { public void registerObserver(Observer observer); public void notifyobs

【转】 java DES ECB模式对称加密解密

最近需要又要使用DES加密数据,要求DES加密出来的数据为对称加密,经过研究,发现了一些问题: 1.DES对称ECB模式加密的数据,长度必须为8的倍数 2.加密的数据,加密后先转码(因为加密后的数据我是转码了),否则解密是乱码格式 一下是源代码: 这个是加密的工具类: package com.palmfu.sql; import java.security.Key; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpe