乐趣区

关于android:Android入门教程-多线程

操作系统能够在同一时刻运行多个程序。例如一边播放音乐,一边下载文件和浏览网页。操作系统将 cpu 的工夫片调配给每一个过程,给人一种并行处理的感觉。

一个多线程程序能够同时执行多个工作。通常,每一个工作称为一个线程(thread),它是线程管制的简称。能够同时运行一个以上线程的程序成为多线程程序(multithreaded)。

多过程和多线程有哪些区别呢?

本质区别在于过程每个过程有本人的一整套变量,而线程则共享数据。线程比过程更轻量级,创立、销毁一个线程比启动新过程的开销要小。

理论利用中,多线程十分有用。例如利用一边解决用户的输出指令,一遍联网获取数据。

Thread

Thread类属于 java.lang 包。

要创立一个线程很简略,新建一个 Thread 对象,并传入一个 Runnable,实现run() 办法。调用 start() 办法启动线程。

Java

Thread t1 = new Thread(new Runnable() {
    @Override
    public void run() {System.out.println("rustfisher said: hello");
    }
});
t1.start();

Java lambda

Thread t1 = new Thread(() -> System.out.println("rustfisher said: hello"));
t1.start();

不要间接调用 run()办法
间接调用 run() 办法不会启动新的线程,而是间接在以后线程执行工作。

咱们来看一个应用了 Thread.sleep() 办法的例子。

Thread t1 = new Thread(() -> {for (String a : "rustfisher said: hello".split("")) {
        try {Thread.sleep(100);
        } catch (InterruptedException e) {e.printStackTrace();
        }
        System.out.print(a);
    }
});
t1.start();

sleep(int)办法会让线程睡眠一个指定的工夫(单位毫秒)。并且须要 try-catch 捕捉 InterruptedException 异样。

中断线程

run() 办法执行完最初一条语句后,或者return,或者呈现了未捕捉的异样,线程将会终止。

应用 Thread 的 interrupt 办法也能够终止线程。调用 interrupt 办法时,会批改线程的中断状态为 true。用isInterrupted() 能够查看线程的中断状态。

但如果线程被阻塞了,就没法检测中断状态。当在一个被阻塞的线程(sleep 或者 wait)上调用 interrupt 办法,阻塞调用将会被 InterruptedException 中断。

被中断的线程能够决定如何响应中断。能够简略地将中断作为一个终止申请。比方咱们被动捕捉InterruptedException

Thread t2 = new Thread(() -> {for (String a : "rustfisher said: hello".split("")) {
        try {Thread.sleep(200);
        } catch (InterruptedException e) {e.printStackTrace();
            System.out.println("被中断 退出线程");
            return;
        }
        System.out.print(a);
    }
});
t2.start();

new Thread(() -> {
    try {Thread.sleep(1000);
    } catch (InterruptedException e) {e.printStackTrace();
    }
    t2.interrupt();}).start();

下面这个小例子展现了用 interrupt() 来中断线程 t2。而线程t2run()办法中捕捉 InterruptedException 后,能够进行本人的解决。

线程的状态

线程有 6 种状态,用枚举类 State 来示意:

  • NEW(新创建)
  • RUNNABLE(可运行)
  • BLOCKED(被阻塞)
  • WAITING(期待)
  • TIMED_WAITING(计时期待)
  • TERMINATED(被终止)

getState() 办法能够获取到线程的状态。

新创建线程

new 一个线程的时候,线程还没开始运行,此时是 NEW(新创建)状态。在线程能够运行前,还有一些工作要做。

可运行线程

一旦调用 start() 办法,线程处于 RUNNABLE(可运行)状态。调用 start() 后并不保障线程会立即运行,而是要看操作系统的安顿。

一个线程开始运行后,它不肯定时刻处于运行状态。操作系统能够让其余线程取得运行机会。一个可运行的线程可能正在运行也可能没在运行。

被阻塞和期待

线程处于被阻塞和期待状态时,它临时不流动。不运行代码,且只耗费起码的资源。直到线程调度器从新激活它。

  • 一个线程试图获取一个外部的对象锁,而该锁被其余线程持有,则这个线程进入阻塞状态。当这个锁被开释,并且线程调度器容许这个线程持有它,该线程变成非阻塞状态。
  • 当线程期待另一个线程告诉调度器,它本人进入期待状态。例如调用 Object.wait() 或者 Thread.join() 办法。
  • 带有超时参数的办法可让线程进入超时期待状态。例如 Thread.sleep()Object.wait(long)Thread.join(long)Lock.tryLock(long time, TimeUnit unit)
被终止

终止的起因:

  • run 办法失常退出
  • 呈现了没有捕捉的异样而终止了 run 办法

线程属性

线程优先级,守护线程,线程组以及解决未捕捉异样的处理器。

线程优先级

Java 中每个线程都有一个优先级。默认状况下,线程继承它的父线程的优先级。可用 setPriority(int) 办法设置优先级。优先级最大为MAX_PRIORITY = 10,最小为MIN_PRIORITY = 1,一般的是NORM_PRIORITY = 5。线程调度器有机会选新线程是,会优先选高优先级的线程。

守护线程

调用 setDaemon(true) 能够切换为守护线程(daemon thread)。守护线程的用处是为其余线程提供服务。例如计时线程。当只剩下守护线程时,虚拟机就退出了。

守护线程不应该去拜访固有资源,如文件和数据库。

未捕捉异样处理器

run()办法里抛出一个未捕捉异样,在线程死亡前,异样被传递到一个用于未捕捉异样的处理器。要应用这个处理器,须要实现接口 Thread.UncaughtExceptionHandler,并且用setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler) 办法把它交给线程。

Thread t3 = new Thread(() -> {
    try {Thread.sleep(5);
    } catch (InterruptedException e) {e.printStackTrace();
        return;
    }
    int x = 0, y = 3;
    int z = y / x; // 成心弄一个异样
});
t3.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    @Override
    public void uncaughtException(Thread t, Throwable e) {System.out.println(t + "有未捕捉异样");
        e.printStackTrace();}
});
t3.start();

运行后,run()办法里抛出 ArithmeticException 异样

Thread[Thread-0,5,main]有未捕捉异样
java.lang.ArithmeticException: / by zero
    at Main.lambda$main$0(Main.java:15)
    at java.lang.Thread.run(Thread.java:748)

也能够用静态方法 Thread.setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler) 给所有的线程装置一个默认处理器。能够在这个默认处理器里做一些工作,例如记录日志。

ThreadGroup 代表着一组线程。也能够蕴含另外的线程组。

ThreadGroup 类实现了 UncaughtExceptionHandler 接口。它的 uncaughtException(Thread t, Throwable e) 办法会有如下操作

  • 如果该线程组有父线程组,则父线程组的 uncaughtException 被调用。
  • 否则,如果 Thread.getDefaultUncaughtExceptionHandler() 返回一个非空处理器,则应用这个处理器。
  • 否则,如果抛出的 ThrowableThreadDeath对象,就什么也不做。
  • 否则,线程的名字和 Throwable 的栈形迹输入到 System.err 上。

Android 零根底入门教程视频参考

退出移动版