分布式三大利器之《异步》 + 自定义线程池规则

一、异步线程最开始使用

在这里插入图片描述
这里橙线有使用到组合模式
所以可以看到开启线程的三种方法
1.继承Thread,实现其run方法
2.由于组合模式,给Thread构造器传入Runnable
即:new Thread(new Runnable{。。。});
3.new Thread(new FutureTask(new Callable(){。。。 }))

public static void main(String[] args) throws ExecutionException, InterruptedException {
    FutureTask future = new FutureTask<String>(new Callable<String>() {
        public String call() throws Exception {
            //模拟需要计算或其他耗时的操作
            TimeUnit.SECONDS.sleep(3);
            return "我是返回的结果...";
        }
    });
    //使用线程池
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    executorService.submit(future);
    
    //获取执行的结果
    String ret = (String) future.get();
    System.out.println(ret);
}

说明:
1.Executor的唯一方法execute无返回值,所以拓展出了ExecutorService接口
2.Runnable的唯一方法run无返回值,所以拓展出Callable接口

线程池

Q:为什么要用线程
异步加速
Q:为什么要用线程池
防止百万请求,每次生成一个线程,资源耗尽
在这里插入图阿描述
四种拒绝策略:

AbortPolicy(默认):直接抛出RejectedExecutionException异常阻止系统正常运行。
CallerRunsPolicy:直接让原线程执行,退化为同步
DiscardoldestPolicy:丢弃最早任务,加入新任务
DiscardPolicy:直接丢弃任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种方案。
这四种内置拒绝策略均实现了RejectExecutionHandler接口

Executors常见线程池:

1.SingleThreadExecutor
在这里插入图片描述
说明:
1)链式无界阻塞队列,不丢弃任务,所以可能会导致OOM

2.FixThreadPool

在这里插入图片描述
说明:
1)和前者类似,核心线程数等于最大线程数,所以3,4参数失效
2)采用无界队列,不会丢失任务,可能会OOM

3.CachedThreadPool
在这里插入图片描述
说明:
1)只有非核心线程,并且线程数最大为2^32-1,可能会OOM
2)60s,杀死空闲非核心线程
3)SynchronousQueue,这个阻塞队列没有存储空间,意味需要立马有线程执行。
4.ScheduledThreadPoolExecutor
在这里插入图片描述
说明:
1)该线程池执行器,可用于定时重复完成任务
2)线程数最大为2^32-1,可能会OOM
3)DelayedWorkQueue,数组实现,有界阻塞,优先队列

自定义线程池

背景:由于以上这四种都有可能造成OOM,并且阿里明确指出禁止使用默认线程池,那么自定义线程池尤为重要。

自定义的规则如下:
由于线程是为了最大程度利用cpu资源,所以需要考虑系统架构的是Cpu密集型还是IO密集型
单核心Cpu总线数量为8

1.IO密集型如下
在这里插入图片描述
2.计算密集型
在这里插入图片描述
最终解决方案:
在这里插入图片描述
说明:
1.积压长度,通过压力测试。
如:该业务允许10s内返回结果,假设该业务耗时1s,通过测试不同队列长度,来保证10s内所有任务的完成。

二、Java 8 特性 CompletableFuture

相比于Future接口有哪些好处呢?
1.可以捕获异常
在这里插入图片描述
2.可以串行执行
在这里插入图片描述
在这里插入图片描述
3.可以组合编排
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用 RedisTemplate 实现分布式锁,具体实现步骤如下: 1. 定义一个自定义注解,用于标识需要加锁的方法。 2. 在方法执行前获取锁,执行后释放锁。 3. 使用 RedisTemplate 操作 Redis,实现分布式锁。 下面是示例代码: ```java @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface DistributedLock { String key(); long expire() default 30000; } @Component @Aspect public class DistributedLockAspect { @Autowired private RedisTemplate<String, String> redisTemplate; @Around("@annotation(distributedLock)") public Object doAround(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable { String key = distributedLock.key(); long expire = distributedLock.expire(); // 获取锁 boolean locked = false; String lockKey = "lock:" + key; String lockValue = UUID.randomUUID().toString(); try { locked = redisTemplate.opsForValue().setIfAbsent(lockKey, lockValue, expire, TimeUnit.MILLISECONDS); if (!locked) { throw new RuntimeException("获取锁失败"); } // 执行方法 return joinPoint.proceed(); } finally { // 释放锁 if (locked) { String value = redisTemplate.opsForValue().get(lockKey); if (lockValue.equals(value)) { redisTemplate.delete(lockKey); } } } } } ``` 在需要加锁的方法上加上 @DistributedLock 注解,指定锁的 key 和过期时间即可。 例如: ```java @Service public class UserService { @Autowired private UserDao userDao; @DistributedLock(key = "user:update:${#userId}") public void updateUser(long userId, String name) { userDao.updateUser(userId, name); } } ``` 这样就可以实现分布式锁了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值