前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java自定义Once方法保障单次执行

Java自定义Once方法保障单次执行

作者头像
FunTester
发布2022-07-08 15:23:37
6040
发布2022-07-08 15:23:37
举报
文章被收录于专栏:FunTesterFunTester

最近在继续学习Go语言的过程中,发现了一个比较神奇的的对象sync.Once,顾名思义,就是执行一次。官方定义的如下:Once是一个只执行一个动作的对象,看包名sync知道这是在并发使用场景。

基础使用方法如下:

代码语言:javascript
复制
// TestOnceSimple once对象简单测试
//  @Description: 
//  @param t
//
func TestOnceSimple(t *testing.T) {
 var once sync.Once
 for i := 0; i < 10; i++ {
  go once.Do(func() {
   log.Println("执行一次")
  })
 }
 time.Sleep(time.Second)
}

for循环里面分别异步执行了10次,但是最终控制台展示如下:

代码语言:javascript
复制
=== RUN   TestOnceSimple
2022/06/19 16:39:08 执行一次
--- PASS: TestOnceSimple (1.00s)
PASS

目前使用到场景中就是在各种配置进行初始化的时候,以防止多个异步同时来执行初始化任务导致异常。比如说,我再使用Redis连接池的时候,首先需要初始化连接池,通常需要一个方法来完成这个过程,大部分时候需要显式调用,除非这个池对于我们项目来讲是基础的功能,程序启动的时候就需要初始化。

这个在我写Java的过程中,用到的HTTP的连接池和MySQL的连接池,而后者就属于需要用的时候的再初始化的场景。还有一种方式,我们可以使用Java单例模式中的懒汉式的解决这个问题。但是我们如果在测试过程中使用不同的对象池的时候,这种方式又显得比较死板不够灵活。

所以在平时处理这种情况的时候,通常我会使用synchronized或者java.util.concurrent.locks.ReentrantLockconcurrent包里面的工具类完成这个需求。具体代码可参考Java单例的懒汉式的实现以及我之前的文章。

之前我对照Go语言的go异步关键字写了Java自定义异步功能实践,写了一个Java版本的fun异步关键字。这次我自然计划要抄一下sync.Once设计。

下面是我的经过自己尝试写了一个简版的:

代码语言:javascript
复制
    static Vector<Integer> ones = new Vector<>();

    static ReentrantLock lock = new ReentrantLock();

    /**
     * 线程安全单次执行,仿照Go语言的once方法
     *
     * @param v
     */
    public static void once(Closure v) {
        try {
            lock.lock();
            int code = v.hashCode();
            if (!ones.contains(code)) {
                ones.add(code);
                v.call();
            }
        } catch (Exception e) {
            logger.warn("once执行方法失败", e);
        } finally {
            lock.unlock();
        }
    }

下面是测试代码:

代码语言:javascript
复制
package com.okcoin.hickwall.presses

import com.okcoin.hickwall.presses.funtester.httpclient.FunHttp 

class OnceTest extends FunHttp {

    public static void main(String[] args) {
        def test = {
            output("FunTester")
        }
        10.times {

            fun {
                once(test)
            }
        }

    }

}

控制台输出:

代码语言:javascript
复制
16:56:22 main 守护线程:Deamon开启!
16:56:22 F-1  FunTester
16:56:23 Deamon 异步线程池等待执行1次耗时:6 ms
16:56:23 Deamon 异步线程池关闭!

从上面内容我们看到,虽然异步执行了10次,但是只有一次真正执行了,实现了预期的需求。

Fun·BUG挖掘机·性能征服者·头顶锅盖·Tester

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-06-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FunTester 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档