线程及线程安全
一、进程 vs 线程
1、进程和线程
进程:是一段运行的程序,是操作系统分配和调度资源的基本单位
线程:是CPU调度的基本单位
一个进程可以拥有多个线程。
2、并行和并发
并行:多个处理器或多核的处理器同时处理多个任务。
并发:单个处理器或单核的处理器同时处理多个任务。
二、线程
1、线程的生命周期
(1)新建New:实例化线程对象,此时的线程处于New的状态
(2)就绪Runnable:当线程对象调用start()方法后,等待CPU调度器的调度,此时线程处于Runnable状态
(3)运行Running:就绪状态下的线程被CPU调度器调度,线程就进入到了运行状态。
(4)阻塞Block:运行状态下的线程因特殊情况被阻塞。如调用了sleep()/join()/wait()等
(5)死亡Dead:线程运行正常结束或报错时,线程进入Dead状态
具体的过程如下:
2、线程阻塞
线程的阻塞根据不同的造成原因又分为等待阻塞、同步阻塞和其他阻塞。
(1)等待阻塞:调用了wait()方法。当调用了wait()方法时,会释放持有对象的锁,只有等待调用notify()/notifyAll()唤醒,才会重新去获取持有对象的锁。
(2)同步阻塞:等待同步监视器,而该同步监视器正被其他线程所持有。
(3)其他阻塞:如调用了sleep()/join()方法,或调用了阻塞式的IO方法等。当调用了sleep()方法时,不会释放持有对象的锁,直至sleep()结束才被释放。
3、线程安全
先看一个简单的例子——售票。有两个窗口同时售票,总票数为100张。
public class TicketsActivity extends AppCompatActivity {
private SaleRunnable mSaleRunnable;
@Override
protected void onCreate(Bundle savedInstanceState){
Log.d("TicketsActivity", "onCreate: ");
super.onCreate(savedInstanceState);
mSaleRunnable = new SaleRunnable();
new Thread(mSaleRunnable).start();
new Thread(mSaleRunnable).start();
}
class SaleRunnable implements Runnable{
private int tickets = 100;
@Override
public void run(){
while(tickets > 0){
Log.d("TicketsActivity"," 售出票号:"+tickets+" thread.id=="+Thread.currentThread().getId());
try{
//假设售出一张票需要1s
Thread.sleep(1000);
}catch(Exception e){
Log.d("TicketsActivity","error="+e);
}
tickets --;
}
}
}
}
打印结果如下:
会出现出同票的问题,实际上这是不可能的,出现这种情况就是因为线程的不安全。保证线程安全就是在多线程中保证线程对一个线程安全的方法或语句进行访问时,其他线程不再进行操作。
线程安全常用的两种方法是使用同步监视器(Synchronized)和锁(Lock)
synchronized和lock的异同点为:
相同点:都是为了线程安全
异同点:当synchronized执行完成,会自动释放同步监视器,而调用了lock()方法后需要调用unlock()之后,其他线程才会获得使用lock的对象。
Synchronized和Lock的具体使用会在下一篇介绍。
4、多线程的实现
多线程的实现有很多种,有如下几种:
a.继承Thread
b.实现Runnable接口
c.Handler
d.AsyncTask
e.线程池
f.HandlerThread
g.IntentService
这里就简单介绍一下HandlerThread的使用吧,其他的比较简单或者后续再做介绍。
HandlerThread
HandlerThread的实现其实是封装了线程池和Handler。具体使用步骤如下:
public class MultiThreadStu extends AppCompatActivity {
private Handler mWorkHandler;
private Handler mUiHandler;
private int count = 0;
@Override
protected void onCreate(Bundle savedInstanceState){
Log.d("MultiThreadStu", "onCreate: ");
super.onCreate(savedInstanceState);
//创建HandlerThread对象
HandlerThread thread = new HandlerThread("test");
//调用HandlerThread的start(),Looper就是在start()方法中创建的,感兴趣的可以看看HandlerThread的源码
thread.start();
//创建子线程的workHandler且执行耗时任务
mWorkHandler = new Handler(thread.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message message = new Message();
message.what = count;
count++;
//通知ui线程
mUiHandler.sendMessage(message);
return false;
}
});
//创建uiHandler用于刷新界面
mUiHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if(msg.what <= 10){
Log.e("MultiThreadStu","msg.what="+msg.what);
//通知子线程继续工作
mWorkHandler.sendEmptyMessage(msg.what);
}
}
};
//触发workHandler
mWorkHandler.sendEmptyMessage(count);
}
}
打印结果: