美文网首页
Android线程

Android线程

作者: Poseidon_Wang | 来源:发表于2016-05-23 11:58 被阅读127次

    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方法后,线程不是立即开启,而是等待系统分配时间片(由于系统是随机分配时间片,所以线程的调度存在不确定性)

    线程状态
    线程状态.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<V>,Future。
    由于Runnable里面的run函数返回为void,因此我们无法观察任务的状态,Callable<V>正好解决了这个问题
    

    public interface Callable<V> {
    /**

    • 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<V> {  
    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<V> implements RunnableFuture<V>
    public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
    }```
    FutrueTask实现了RunnableFuture<v>,RunnableFuture<v>又继承自Runnable,Future<v>,Callable<v>经常搭配ExcutorService一起使用

    public FutureTask(Callable<V> callable) {}
    public FutureTask(Runnable runnable, V result) {}```
    FutureTask提供了两个构造函数,实质都是实现Runnable与Future<v>接口,[FutureTask,Callable<V>使用](http://www.cnblogs.com/dolphin0520/p/3949310.html)
    
    ----
    写作思路大抵发散性的 有相关的就查阅下,篇幅比较长,若有错误请大家指正,下次接着写线程池

    相关文章

      网友评论

          本文标题:Android线程

          本文链接:https://www.haomeiwen.com/subject/xryarttx.html