1、Android中线程的常见用法
(1)继承 Thread
class MyThread extends Thread{
@Override
public void run(){
//处理具体的逻辑
}
}
new MyThread().start(); //启动此线程
//使用匿名类
new Thread(){
@Override
public void run(){
//处理具体的逻辑
}
}.start();
(2)实现 Runnable
class MyThread implements Runnable{
@Override
public void run(){
//处理具体的逻辑
}
}
MyThread myThread = new MyThread();
new Thread(myThread).start();
//使用匿名类
new Thread(new Runnable(){
@Override
public void run(){
//处理具体的逻辑
}
}).start();
2、线程的状态转换
3、线程安全
(1)定义
线程安全:这里讨论的线程安全,以多个线程之间存在共享数据访问为前提,它需要保证对对象单次的操作是线程安全的。
线程兼容:指对象本身并不是线程安全的,但是可以通过在调用端正确地使用同步手段来保证对象在并发环境中可以安全地使用。比如,ArrayList 和 HashMap 等是线程兼容的。
(2)使用“互斥同步”来实现线程安全
同步:多个线程并发访问共享数据时,保证共享数据在同一时刻只被一条(或者一些,当使用信号量的时候)线程使用。
互斥:实现同步的一种手段,临界区、互斥量和信号量都是常见的互斥实现方式。
在Java中,最基本的互斥同步手段就是Synchronized关键字。
Synchronized关键字:
- 一种块结构的同步语法
- 经过Javac编译之后,会在同步块的前后分别形成monitorenter和monitorexit这两个字节码指令。这两个字节码指令都需要一个reference类型的参数来指明要锁定和解锁的对象
- 如果Java代码中的synchronized明确指定了对象参数,那就以这个对象的引用作为reference;如果synchronized修饰的方法类型是实例方法,取 ”代码所在的对象实例“ 来作为线程要持有的锁;如果synchronized修饰的方法类型是类方法,取 ”类的Class对象“ 来作为线程要持有的锁。
- 在执行 monitorenter 指令时,首先要去尝试获取对象的锁,如果这个对象没被锁定,或者当前线程已持有该对象的锁,就把锁的计数器的值加一,而在执行 monitorexit 指令时,会将锁计数器的值减一。一旦计数器的值为零,锁随即就被释放了。(注意:被synchronized修饰的同步块对同一条线程来说是可重入的,即同一线程反复进入同步块也不会出现自己把自己锁死的情况)
- 如果获取对象的锁失败,那当前线程就应当被阻塞等待,直到请求锁定的对象被持有它的线程释放为止。(注意:被synchronized修饰的同步块在持有锁的线程执行完毕并释放锁之前,会无条件地阻塞后面其他线程的进入)
4、ThreadLocal
实现线程本地存储的功能
ThreadLocal提供了一种与众不同的线程安全方式