作者:mobiledu2502860117 | 来源:互联网 | 2023-09-25 20:00
锁优化有3个方向:
1.减少持有锁的时间:例如,将CPU密集和I/O密集的任务移到锁外,可以有效减少持有锁的时间,从而降低其他线程的阻塞时间。
2.减小加锁的粒度:将单个独占锁变为多个锁,从而将加锁请求均分到多个锁上,有效降低对锁的竞争。但是,增加锁的前提是多线程访问的变量间相互独立,如果多线程需要同时访问多个变量,则很难进行锁分解,因为要维持原子性。
3.放弃使用独占锁,使用非阻塞算法来保证并发安全。例如,使用并发容器、读写锁、不可变对象、原子变量、线程封闭等技术。
本文介绍减小锁粒度的方法:
public class ServerStatus {public final Set users;public final Set queries;public ServerStatus() {users = new HashSet<>();queries = new HashSet<>();}/*** 独占锁意味着增加资源不能提升程序吞吐量,可伸缩性很差* @param user*/public synchronized void addUser(String user) {users.add(user);}public synchronized void addQuery(String q) {queries.add(q);}public synchronized void removeUser(String user) {users.remove(user);}public synchronized void removeQuery(String query) {users.remove(query);}
} /*** 锁分解技术是减小了锁粒度,将锁住所有变量的全局锁变为锁住部分变量的局部锁。* 锁分解能提升吞吐量的原理是将对一个锁的竞争均摊到2个锁上,从而降低了对单个锁的请求频率,有效地降低了竞争程度。* 不足:与独占锁相比,锁分解技术在多处理器系统中只能将吞吐量提高一倍,可伸缩性还是受到限制。*/
public class ServerStatusLockDecompose {public final Set users;public final Set queries;public ServerStatusLockDecompose() {users = new HashSet<>();queries = new HashSet<>();}/*** 独占锁意味着增加资源不能提升程序吞吐量,可伸缩性很差* @param user*/public void addUser(String user) {synchronized(users) {users.add(user);}}public void addQuery(String q) {synchronized(queries) {queries.add(q);}}public void removeUser(String user) {synchronized(users) {users.remove(user);}}public void removeQuery(String query) {synchronized(queries) {queries.remove(query);}}
} 当处理器增加时,分解锁的性能不能持续提升,所以,可以使用分段锁,要求是数据独立同分布,每个锁保护一部分数据。
/*** buckets[n]由locks[n % N_LOCKS]来保护*/
public class StrippedMap {private static final int N_LOCKS = 16;private final Node[] buckets;private final Object[] locks;private static class Node{Object key;Object value;Node next;Node(Object key, Object value) {this.value = value;this.key = key;}void setNext(Node next) {this.next = next;}}public StrippedMap(int numBuckets) {buckets = new Node[numBuckets];locks = new Object[N_LOCKS];for(int i = 0; i } 对锁的优化,是建立在保证程序正确性的基础上的,所以,先保证程序能正常运行,当吞吐量达不到期望时,才能考虑性能优化,过早的优化就是灾难。
参考《Java并发编程实战》