Android如何保证一个线程最多只能有一个Looper?,android音乐播放器项目源码

long currentThreadId = Thread.currentThread().getId();

Looper l = looperRegistry.get(currentThreadId);

if (l != null)

throw new RuntimeException(“Only one Looper may be created per thread”);

looperRegistry.put(currentThreadId, new Looper(true));

}

}

}

上述方法对Looper.class对象进行了加锁,这些加锁开销有可能造成性能瓶颈。

有没有更好的方法实现Looper.prepare()方法?看一看Android的中Looper的源码。

public class Looper {

static final ThreadLocal sThreadLocal = new ThreadLocal();

public static void prepare() {

prepare(true);

}

private static void prepare(boolean quitAllowed) {

if (sThreadLocal.get() != null) {

throw new RuntimeException(“Only one Looper may be created per thread”);

}

sThreadLocal.set(new Looper(quitAllowed));

}

}

prepare()方法中调用了ThreadLocal的get和set方法,然而整个过程没有添加同步锁,Looper是如何实现线程安全的?

2. ThreadLocal

ThreadLocal位于java.lang包中,以下是JDK文档中对该类的描述

Implements a thread-local storage, that is, a variable for which each thread has its own value. All threads share the same ThreadLocal object, but each sees a different value when accessing it, and changes made by one thread do not affect the other threads. The implementation supports null values.

大致意思是,ThreadLocal实现了线程本地存储。所有线程共享同一个ThreadLocal对象,但不同线程仅能访问与其线程相关联的值,一个线程修改ThreadLocal对象对其他线程没有影响。

ThreadLocal为编写多线程并发程序提供了一个新的思路。如下图所示,我们可以将ThreadLocal理解为一块存储区,将这一大块存储区分割为多块小的存储区,每一个线程拥有一块属于自己的存储区,那么对自己的存储区操作就不会影响其他线程。对于ThreadLocal,则每一小块存储区中就保存了与特定线程关联的Looper。

  1. ThreadLocal的内部实现原理

3.1 Thread、ThreadLocal和Values的关系

Thread的成员变量localValues代表了线程特定变量,类型为ThreadLocal.Values。由于线程特定变量可能会有多个,并且类型不确定,所以ThreadLocal.Values有一个table成员变量,类型为Object数组。这个localValues可以理解为二维存储区中与特定线程相关的一列。

ThreadLocal类则相当于一个代理,真正操作线程特定存储区table的是其内部类Values。

3.2 set方法

public void set(T value) {

Thread currentThread = Thread.currentThread();

Values values = values(currentThread);

if (values == null) {

values = initializeValues(currentThread);

}

values.put(this, value);

}

Values values(Thread current) {

return current.localValues;

}

1

2

3

4

5

6

7

8

9

10

11

12

既然与特定线程相关,所以先获取当前线程,然后获取当前线程特定存储,即Thread中的localValues,若localValues为空,则创建一个,最后将value存入values中。

void put(ThreadLocal<?> key, Object value) {

cleanUp();

// Keep track of first tombstone. That’s where we want to go back

// and add an entry if necessary.

int firstTombstone = -1;

for (int index = key.hash & mask;; index = next(index)) {

Object k = table[index];

if (k == key.reference) {

//
Replace existing entry.

table[index + 1] = value;

return;

}

if (k == null) {

if (firstTombstone == -1) {

// Fill in null slot.

table[index] = key.reference;

table[index + 1] = value;

size++;

return;

}

// Go back and replace first tombstone.

table[firstTombstone] = key.reference;

table[firstTombstone + 1] = value;

tombstones–;

size++;

return;

}

// Remember first tombstone.

if (firstTombstone == -1 && k == TOMBSTONE) {

firstTombstone = index;

}

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24
one.

if (firstTombstone == -1 && k == TOMBSTONE) {

firstTombstone = index;

}

}

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值