Android线程

Android的应用层都是Java写的,所以很多语法上的东西就是Java的,只不过某些类在原有基础上进行了包装,毕竟android跟java web,se之类的生产环境不一样,而线程又是java中一块很重要的知识,线程控制的好不好也关系到应用性能提升大不大,毕竟不是Java出身,所以简单的说说java的线程

多线程

扯到线程,就不免会说道进程,简答来数进程就是内存中运行的应用程序有独立的内存空间,而线程则是进程的组成,线程即达成目标的一个任务。
那么我们为什么使用多线程呢?如今cpu已经进入4核,八核时代,如何充分利用硬件资源去实现一个程序催生了多线程。
举个简单的例子,运一批货,在一个双车道的道路上,如果按顺序发车的话,货物到达肯定要慢点,同时发货的话,理想情况时间就少了一半。

Java的多线程
一般Java中实现多线程无非两种方式:
  • 继承Thread
class NewThread extends Thread {    
@Override    
public void run() {        
        super.run();    
        }
}
  • new Thread将任务放到Runnable里面
new Thread(new Runnable() {    
@Override    
public void run() {            
      }
}).start();

需要注意的是,调用start方法后,线程不是立即开启,而是等待系统分配时间片(由于系统是随机分配时间片,所以线程的调度存在不确定性)

线程状态
Android线程_第1张图片
线程状态.png
  • 新建状态(New):**当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
  • 就绪状态(Runnable):**当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
  • 运行状态(Running):**当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
  • 阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
    1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
    2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
    3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
  • 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
线程优先级

Java的线程是具有优先级的,可以通过setPriority()设置线程的优先级,控制线程的重要性(拥有较大机会获取系统调度),Thread有3个控制线程优先级的常量

  • static int MAX_PRIORITY ----10
  • static int MIN_PRIORITY-----1
  • static int NORM_PRIORITY---5
常见线程常用函数

1.sleep(long mills):让当前线程休眠指定的毫秒数
2.join():让主线程等待调用该函数的线程结束再执行(所在线程等待调用该方法的线程变量所在的线程执行完毕)
应用情形:当主线程需要实时使用子线程的处理结果,有点像阻塞式的编程
3.yield():暂停当前线程,让出时间片
实质是将该线程调回到runnable状态重新等待调度,高优先级线程会被先调用,同等级无法保证让出时间片(进入了统一等待队列,系统还是会选中当前线程)
4.setPriority(int priority):上面有说过
5.interrupt():野蛮方式中断线程,可能会导致资源无法释放
6.wait():等待拥有同样资源锁的线程的执行,线程同步的一个方法,主要关系到对资源锁定问题,后面讨论
7.notify():唤醒拥有同样资源锁的线程


备注:sleep()与wait()区别:sleep的同时不释放同步锁,也就是说sleep的同时拥有同样资源锁的线程不会拿到时间片,而wait()的时候是释放同步锁,让其他拥有同等资源锁的线程获得时间片(必须放在synchronized块内)


线程同步问题

这个应该是线程里面最重要,也是最难的部分了,主要由于系统调度的不确定性引起,一般不做线程同步的话,出现了某些问题,调试都很难调试出来
数据的同步在数据库里面非常常见,设想线程A,B同时对一个变量进行++操作

int res = 0;
class A extends Thread {    
@Override   
 public void run() {       
super.run();       
 res=res+1;       
System.out.print("A:res" + res);    
}}
class B extends Thread {   
 @Override    
public void run() {        
super.run();       
 res=res+1;        
System.out.print("B:res" + res);    }}```
上述代码会有两种不同的输出
A:1
B:2
或者
B:1
A:2
这可能跟我预想的结果就不一样了,因此我们需要对资源进行同步
######synshronized关键字
这是用来加同步锁的关键字,他有两种作用域
1. 对象:某个对象内synchronized methodA(){},可以锁住这个对象的该方法(若该对象拥有多个synchronized方法,加锁后其它synchronized方法也无法调用),但不影响不同对象
2. 类:synchronized static methodA(){},对所有对象起效
除了方法前可以加synchronized,某个区块也可以加,他们的实质都是锁对象

```synchronized methodA(){} //锁对象 
synchronized static methodA(){} //锁类```
等同于 
```methodA(){synchronized(obj){} } //锁对象 
methodA(){
synchronized(obj.class){}}```
synchronized搭配wait(),notify()方法使用,wait()调用后,不执行wait()后面的代码,notify()后继续执行上次wait()后的代码

######lock同步锁
方便的解决同步问题的另一方案

class X {
// 显示定义Lock同步锁对象,此对象与共享资源具有一对一关系
private final Lock lock = new ReentrantLock();
public void m(){
// 加锁 lock.lock();
//... 需要进行线程安全同步的代码
// 释放Lock锁
lock.unlock(); } }


可以参考下Condition实现

######线程数据传递

由于线程的不确定性,所以线程间的通信,也不像普通的同步模式下的通信
1. 构造方法传递数据 由于构造方法是线程一开始就传入所以不存在同步问题,可通过重载构造方法传入参数
2. 通过公开方法赋值,类的属性器赋值或者读取
前两个都建立在宿主线程与被调线程的通信,下面就是线程与线程之间(并无直接关联)
3. 通过同步控制,访问共有对象(synchronized,wait,notify等)
4. 管道流(这个不是很了解,望高手指教)
---
接下来就谈谈Runnable,Callable,Future。
由于Runnable里面的run函数返回为void,因此我们无法观察任务的状态,Callable正好解决了这个问题

public interface Callable {
/**

  • Computes a result, or throws an exception if unable to do so.
  • @return computed result
  • @throws Exception if unable to compute a result
    */
    V call() throw Exception;
    }```
    Future又是什么东西呢,
public interface Future {  
boolean cancel(boolean mayInterruptIfRunning);   
boolean isCancelled();   
boolean isDone();
V get() throws InterruptedException,ExecutionException;   
V get(long timeout, TimeUnit unit)        
throws InterruptedException, ExecutionException, TimeoutException;
}```
* cancel取消任务
* isCancelled 返回任务是否被取消
* get 获取任务这行结果,阻塞方法,等到任务正常完成才会返回值
* get(long,TimeUnit)在规定时间内无返回结果就返回null

所以Future只是个接口因此我们只能使用它的实现

public class FutureTask implements RunnableFuture
public interface RunnableFuture extends Runnable, Future {
void run();
}```
FutrueTask实现了RunnableFuture,RunnableFuture又继承自Runnable,Future,Callable经常搭配ExcutorService一起使用

public FutureTask(Callable callable) {}
public FutureTask(Runnable runnable, V result) {}```
FutureTask提供了两个构造函数,实质都是实现Runnable与Future接口,[FutureTask,Callable使用](http://www.cnblogs.com/dolphin0520/p/3949310.html)

----
写作思路大抵发散性的 有相关的就查阅下,篇幅比较长,若有错误请大家指正,下次接着写线程池

你可能感兴趣的:(Android线程)