Android 高性能编码一:多线程并发或分布式提高TPS

本文介绍如何通过多线程技术优化Android应用程序的TPS(每秒事务处理数),包括防止线程阻塞、提升运行速度、分布式处理、线程池复用及合理设置线程优先级等方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TPS(Transaction Per Second)
TPS为每秒处理的事务数,是系统吞吐量的指标,在搜索系统中也用QPS(Query Per Second)衡量。TPS一般与响应时间反相关。

通常所说的性能问题就是指响应时间过长、系统吞吐量过低。

Android高性能编码一:多线程并发或分布式提高TPS

Android高性能编码二:利用缓存提高TPS

Android高性能编码三:数据结构和算法优化

Android高性能编码四:代码优化

多线程优化TPS主要有以下几种方式

1.多线程并发,防止线程阻塞带来的性能损失


Java线程存在创建、可运行、阻塞、运行中、死亡等生命周期,每个线程在运行的过程中,不可避免的要被阻塞,等待时机成熟再运行,这个时候CPU的资源不能浪费,就需要再起起一个线程去做其他事情,正如烧水的例子,你可以在等待水开的过程中,准备好茶具、茶叶,然后水开之后就可以泡茶,如果你单线程操作的话,等你准备好之后,水也凉了半截了,这就是一个多线程的例子,反正闲着也是闲着。多线程可以在比较短的时间里,做完一项复杂的工作。这个熟悉的例子是我们最开始学习多线程时就明白的道理。

在实际的运行过程中,Android在调用接口时,会使用到很多IO接口,而IO很多是阻塞的,比如网络操作,为防止阻塞带来的性能损失,最好另起一个线程。

Android系统其实已经注意到了这点,如果你在主线程做非常耗时的操作,UI线程5秒没有反应的话就会造成ANR,Android系统的这种限制,就要求开发者耗时操作必须另起一个线程,实际上就是一个提高性能,提升用户体验的一个设定。而且,前面提到的网络操作,Android系统本身就要求在子线程里面做网络操作,另外,Android 多方便开发者使用多线程,设计了很多多线程组件。

可以参考文章http://www.cnblogs.com/bugly/p/5519510.html,作者详细的介绍了Android系统为了多线程设计的组件的使用场景。


2.多线程并发,提升运行速度。

在使用多线程时,一定要知道一个道理:处理速度的最终决定因素是CPU、内存等,在单CPU(无论多少核)上,分配CPU资源的单位是“进程”而不是“线程”。
我们可以做一个简单的试验:

假设我要拷贝100万条数据,单CPU电脑,用一个进程,在单线程的情况下,CPU占用率为5%,耗时1000秒。那么当在这个进程下,开辟10个线程同时去运行,是不是CPU占用率增加到50%,耗时减少到100秒呢?显然不是。我实测出来的情况是这样的:

“CPU占用率仍然是5%,总耗时仍然是1000秒。且每个线程的运行时间也为1000秒。”

重点是后面那句,怎么理解?意味着什么?
我的理解如下:进程只有一个,所以分配的CPU资源是一定的,多线程只不过是轮流抢占CPU而已,并不会真正提高处理速度。这意味着,多线程的作用主要在于提高了并发数量,比如http请求,如果是单线程,一次只能接收一个请求,多线程则可以同时接收多个请求。

所以,单核的CPU多线程并不能提升速度,而多核CPU使用多线程将提升速度。线程池核心线程数的设置就是考虑到了这个特性。

一般线程池核心线程数的设置:

IO密集型 = CPU核数 * 10 

计算密集型 = CPU核数+1


3.多线程分布式,使业务逻辑清晰严谨

通过巧妙的结合使用synchronized和Thread的join、wait、notify、notifyAll等方法会使代码更严谨,高效。像录制视频的例子,为保证视频的质量,音频和视频的录制编码必须严谨,就是巧妙的使用了线程。


4.巧用线程池提高线程复用

前面提到了线程的多个生命周期,像Java的所有类一样,线程的创建和销毁也会影响到性能,销毁的时候大量的对象和内存需要回收,gc时势必会卡一下,如果有大量的线程要使用的话,最好使用线程池,它可以很好的管理线程,并提高线程重用度,降低线程的创建和销毁


5.设置线程的优先级,让紧急的任务尽快处理

系统对线程的调度,按照线程的优先级,Android系统有两个API可以设置优先级

a.方式一

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //设置线程优先级为后台,这样当多个线程并发后很多无关紧要的线程分配的CPU时间将会减少,有利于主线程的处理,相关的Thread优先级 Android就Android平台专有的定义罗列有以下几种:

  int THREAD_PRIORITY_AUDIO //标准音乐播放使用的线程优先级

  int THREAD_PRIORITY_BACKGROUND //标准后台程序

  int THREAD_PRIORITY_DEFAULT // 默认应用的优先级

  int THREAD_PRIORITY_DISPLAY //标准显示系统优先级,主要是改善UI的刷新

  int THREAD_PRIORITY_FOREGROUND //标准前台线程优先级

  int THREAD_PRIORITY_LESS_FAVORABLE //低于favorable

  int THREAD_PRIORITY_LOWEST //有效的线程最低的优先级

  int THREAD_PRIORITY_MORE_FAVORABLE //高于favorable

  int THREAD_PRIORITY_URGENT_AUDIO //标准较重要音频播放优先级

  int THREAD_PRIORITY_URGENT_DISPLAY //标准较重要显示优先级,对于输入事件同样适用.

    field public static final int THREAD_PRIORITY_AUDIO = -16; // 0xfffffff0
    field public static final int THREAD_PRIORITY_BACKGROUND = 10; // 0xa
    field public static final int THREAD_PRIORITY_DEFAULT = 0; // 0x0
    field public static final int THREAD_PRIORITY_DISPLAY = -4; // 0xfffffffc
    field public static final int THREAD_PRIORITY_FOREGROUND = -2; // 0xfffffffe
    field public static final int THREAD_PRIORITY_LESS_FAVORABLE = 1; // 0x1
    field public static final int THREAD_PRIORITY_LOWEST = 19; // 0x13
    field public static final int THREAD_PRIORITY_MORE_FAVORABLE = -1; // 0xffffffff
    field public static final int THREAD_PRIORITY_URGENT_AUDIO = -19; // 0xffffffed
    field public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8; // 0xfffffff8
数值越小优先级越低,

优先级越高的线程被优先处理

04-23 11:20:09.312 17761-17777/com.vrseen.test2 D/TestThreadPriority: Thread B os priority: -19 loop count: 99859
04-23 11:20:09.312 17761-17776/com.vrseen.test2 D/TestThreadPriority: Thread A os priority: 19 loop count: 89701
04-23 11:20:09.312 17761-17777/com.vrseen.test2 D/TestThreadPriority: Thread B os priority: -19 loop count: 99860
04-23 11:20:09.312 17761-17776/com.vrseen.test2 D/TestThreadPriority: Thread A os priority: 19 loop count: 89702
04-23 11:20:09.312 17761-17776/com.vrseen.test2 D/TestThreadPriority: Thread A os priority: 19 loop count: 89703
04-23 11:20:09.312 17761-17777/com.vrseen.test2 D/TestThreadPriority: Thread B os priority: -19 loop count: 99861
04-23 11:20:09.312 17761-17776/com.vrseen.test2 D/TestThreadPriority: Thread A os priority: 19 loop count: 89704

线程B优先级-19比低优先级19的线程A执行多了将近10万的loop,多执行了10万多次。


b.方式二

java.lang.Thread.setPriority (int priority)
priority:【1, 10】,低优先级 -> 高优先级。

   /**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;


-23 11:15:27.804 13432-13448/com.vrseen.test2 D/TestThreadPriority: Thread B java priority: 1 loop count: 75212
04-23 11:15:27.804 13432-13448/com.vrseen.test2 D/TestThreadPriority: Thread B java priority: 1 loop count: 75213
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99860
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99861
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99862
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99863
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99864
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99865
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99866
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99867
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99868
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99869
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99870
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99871
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99872
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99873
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99874
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99875
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99876
04-23 11:15:27.804 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 99877
......
04-23 11:15:27.805 13432-13447/com.vrseen.test2 D/TestThreadPriority: Thread A java priority: 10 loop count: 100000

线程优先级数值为10的比数值为1的线程多执行25万次

方式二效果更好。


demo参考文章

http://blog.sina.com.cn/s/blog_601cbd070100njbi.html


<think>好的,用户想了解如何使用Redisson分布式锁实现高并发环境下的库存管理系统,确保多库并发控制的正确性和效率。我需要结合他们提供的引用内容来构建个全面的回答。 首先,根据引用[1]和[2],Redisson是分布式锁的推荐方案,因为它解决了数据库和缓存不致的问题,并且符合CAP原理。用户可能关心Redisson的基本原理和如何集成到库存系统中。我需要解释Redisson的锁机制,比如可重入锁、锁续期等。 然后,库存管理通常涉及扣减库存的操作,必须保证原子性。这里需要提到使用Redis的原子操作,比如Lua脚本,者结合Redisson的RLock。引用[3]提到了锁等待时间,这可能和锁的超时设置有关,需要说明如何合理配置锁的过期时间,避免死锁和长时间阻塞。 接下来是多库并发控制的问题。库存系统可能有多个仓库数据库,分布式锁需要跨所有节点协调。根据引用[1]中的RedLock算法,可能需要多个独立的Redis实例来实现更可靠的锁。不过Redisson已经支持RedLock,可以介绍如何配置和使用。 另外,引用[4]提到锁的粒度问题,使用userid作为锁的key,这里库存管理可能需要以商品ID库存ID作为锁的键,确保同商品的库存操作串行化,避免超卖。需要强调锁的粒度要合适,太粗会影响并发性能,太细会增加复杂度。 还需要考虑高并发下的性能优化,比如分段锁。引用[3]提到了Go的分段加锁Demo,可能可以借鉴到Java中,将库存分成多个段,每个段单独加锁,提高并发度。例如,将库存拆分为多个子库存,减少锁竞争。 此外,异常处理也很重要,比如锁的自动续期、避免锁泄漏。Redisson的看门狗机制可以自动延长锁的持有时间,防止业务未完成时锁过期。需要提醒用户正确处理锁的获取和释放,确保在异常情况下也能释放锁,比如在finally块中释放。 最后,分布式事务和幂等性可能也是需要考虑的,引用[2]提到了接口的幂等性,库存操作需要保证即使重复请求也不会多次扣减。可以通过唯事务ID版本号机制来实现。 总结回答结构:先介绍Redisson分布式锁的核心机制,然后详细说明库存扣减流程,包括锁的获取、原子操作、多库处理,接着讨论锁的优化如分段锁和RedLock,最后强调异常处理和监控。这样用户能步步了解如何正确高效地实现分布式库存管理。</think>### Redisson分布式锁在库存管理系统中的实现实践 #### 、核心机制设计 1. **可重入锁机制** Redisson的`RLock`支持线程级别的重入特性,同线程可重复获取锁,防止死锁。适用于需要嵌套调用的库存操作场景: ```java RLock lock = redissonClient.getLock("product_stock:1001"); lock.lock(10, TimeUnit.SECONDS); // 设置自动过期时间[^1] ``` 2. **看门狗自动续期** 当未显式设置`leaseTime`参数时,Redisson会启动后台线程每10秒检测锁状态并自动续期(默认30秒有效期),避免业务未完成时锁过期[^1]。 #### 二、库存扣减流程实现 ```java public boolean deductStock(String productId, int quantity) { String lockKey = "stock_lock:" + productId; RLock lock = redissonClient.getLock(lockKey); try { // 尝试获取锁(等待5秒,锁持有30秒) if (lock.tryLock(5, 30, TimeUnit.SECONDS)) { int currentStock = redisTemplate.opsForValue().get(productId); if (currentStock >= quantity) { redisTemplate.opsForValue().decrement(productId, quantity); return true; } return false; } } finally { lock.unlock(); } } ``` #### 三、多库并发控制方案 1. **库存分片策略** 采用分段锁提升并发能力,将总库存拆分为N个分片: ```java int shard = productId.hashCode() % 16; String lockKey = "stock_shard_lock:" + shard; ``` 2. **跨库事务协调** 使用RedLock算法实现跨多Redis节点的强致性: ```java RLock lock1 = redissonClient1.getLock("lockKey"); RLock lock2 = redissonClient2.getLock("lockKey"); RedissonRedLock redLock = new RedissonRedLock(lock1, lock2); ``` #### 四、性能优化实践 | 优化维度 | 实施方法 | 效果提升 | |----------------|-----------------------------------|---------------------------| | 锁粒度控制 | 按商品ID+仓库ID组合锁定 | 降低锁竞争概率 | | 热点库存拆分 | 将1000件库存拆分为10个100件的分片 | 并发能力提升8-10倍 | | 预扣库存策略 | 使用Redis原子操作提前扣减虚拟库存 | 减少数据库压力 | #### 五、异常处理关键点 1. **网络分区防护** 设置合理的`lockWatchdogTimeout`(默认30秒),配合`innodb_lock_wait_timeout`(数据库行锁超时)形成双层保护[^3] 2. **幂等性保证** 为每个操作生成唯事务ID: ```sql UPDATE inventory SET stock=stock-? WHERE product_id=? AND version=? ``` #### 六、监控指标建议 1. 锁等待时间百分位(P99 ≤ 50ms) 2. 库存操作TPS与锁获取成功率关联分析 3. 分片锁的竞争热度分布
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值