前言
- 在
Android
开发中,多线程的使用十分常见 - 今天,我将全面解析多线程其中一种常见用法:
Runnable
接口
目录
![](http://upload-images.jianshu.io/upload_images/944365-515f7ba0dc1d758b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp)
1. 简介
![](http://upload-images.jianshu.io/upload_images/944365-e45b4a0c078d1485.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp)
2. 使用讲解
2.1 使用步骤
![](http://upload-images.jianshu.io/upload_images/944365-74338b1f2b0777a7.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/190/format/webp)
特别注意:
-
Java
中真正能创建新线程的只有Thread
类对象 - 通过实现
Runnable
的方式,最终还是通过Thread
类对象来创建线程
所以对于 实现了
Runnable
接口的类,称为 线程辅助类;Thread
类才是真正的线程类
2.2 具体使用
// 步骤1:创建线程辅助类,实现Runnable接口
class MyThread implements Runnable{
....
@Override
// 步骤2:复写run(),定义线程行为
public void run(){
}
}
// 步骤3:创建线程辅助对象,即 实例化 线程辅助类
MyThread mt=new MyThread();
// 步骤4:创建线程对象,即 实例化线程类;线程类 = Thread类;
// 创建时通过Thread类的构造函数传入线程辅助类对象
// 原因:Runnable接口并没有任何对线程的支持,我们必须创建线程类(Thread类)的实例,从Thread类的一个实例内部运行
Thread td=new Thread(mt);
// 步骤5:通过 线程对象 控制线程的状态,如 运行、睡眠、挂起 / 停止
// 当调用start()方法时,线程对象会自动回调线程辅助类对象的run(),从而实现线程操作
td.start();
2.3 简便使用:匿名类
很多情况下,开发者会选择一种更加方便的方法去创建线程:匿名类
// 步骤1:通过匿名类 直接 创建线程辅助对象,即 实例化 线程辅助类
Runnable mt = new Runnable() {
// 步骤2:复写run(),定义线程行为
@Override
public void run() {
}
};
<span class="hljs-comment">// 步骤3:创建线程对象,即 实例化线程类;线程类 = Thread类;</span>
Thread mt1 = <span class="hljs-keyword">new</span> Thread(mt, <span class="hljs-string">"窗口1"</span>);
<span class="hljs-comment">// 步骤4:通过 线程对象 控制线程的状态,如 运行、睡眠、挂起 / 停止</span>
mt1.start();
2.3 区别
2种方法本质相同,但是各有优劣势 & 不同的应用场景:
大家可根据自己的需求场景来选择具体的使用方法
![](http://upload-images.jianshu.io/upload_images/944365-d13f2a254202bed8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/770/format/webp)
为了让大家理解更加深刻,下面例子我都会采用方法1 = 常规方式 来演示
3. 实例应用
实例1
- 应用场景:创建两个线程-实现两个相同的耗时任务
- 实例说明:实现2个窗口同时卖火车票;每个窗口卖100张,卖票速度都是1s/张
建议先下载Demo再看分析:Carson_Ho的Github地址:多线程之继承Thread类
- 具体实现
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.carson_ho.demoforrunnable.MainActivity">
//设置一个按钮用以启动线程
<span class="hljs-tag"><<span class="hljs-name">Button</span>
<span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/button"</span>
<span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"wrap_content"</span>
<span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span>
<span class="hljs-attr">android:text</span>=<span class="hljs-string">"点击开始卖票"</span> /></span>
</RelativeLayout>
MainActivity.java
package com.example.carson_ho.demoforrunnable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
<span class="hljs-comment">//主布局中定义了一个按钮用以启动线程</span>
Button button;
<span class="hljs-comment">//步骤1:创建线程类,实现Runnable接口</span>
<span class="hljs-keyword">private</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyThread1</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Runnable</span></span>{
<span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> ticket = <span class="hljs-number">100</span>;<span class="hljs-comment">//一个窗口有100张票</span>
<span class="hljs-comment">//在run方法里复写需要进行的操作:卖票速度1s/张</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span></span>{
<span class="hljs-keyword">while</span> (ticket><span class="hljs-number">0</span>){
ticket--;
System.out.println(Thread.currentThread().getName() + <span class="hljs-string">"卖掉了1张票,剩余票数为:"</span>+ticket);
<span class="hljs-keyword">try</span> {
Thread.sleep(<span class="hljs-number">1000</span>);<span class="hljs-comment">//卖票速度是1s一张</span>
} <span class="hljs-keyword">catch</span> (InterruptedException e) {
e.printStackTrace();
}
}
}
}
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(Bundle savedInstanceState)</span> </span>{
<span class="hljs-keyword">super</span>.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
<span class="hljs-comment">//Button按下时会开启一个新线程执行卖票</span>
button = (Button) findViewById(R.id.button);
button.setOnClickListener(<span class="hljs-keyword">new</span> View.OnClickListener() {
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span><span class="hljs-params">(View v)</span> </span>{
<span class="hljs-comment">//步骤2:创建线程类的实例</span>
<span class="hljs-comment">//创建二个线程,模拟二个窗口卖票</span>
MyThread1 mt1 = <span class="hljs-keyword">new</span> MyThread1();
MyThread1 mt2 = <span class="hljs-keyword">new</span> MyThread1();
Thread mt11 = <span class="hljs-keyword">new</span> Thread(mt1, <span class="hljs-string">"窗口1"</span>);
Thread mt22 = <span class="hljs-keyword">new</span> Thread(mt2, <span class="hljs-string">"窗口2"</span>);
<span class="hljs-comment">//步骤3:调用start()方法开启线程</span>
<span class="hljs-comment">//启动二个线程,也即是窗口,开始卖票</span>
mt11.start();
mt22.start();
}
});
}
}
- 测试结果
![](http://upload-images.jianshu.io/upload_images/944365-72ba7f7759d1fba1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp)
- Demo源码地址
Carson_Ho的Github地址:多线程之继承Thread类
实例2
- 应用场景:创建两个线程-实现两个不同的耗时任务
- 实例说明:实现2个窗口同时卖火车票;每个窗口卖100张,但卖票速度不同:窗口1是1s/张,窗口2是3s/张
建议先下载Demo再看分析:Carson_Ho的Github地址:多线程之继承Thread类
- 具体实现
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.carson_ho.demoforrunnable2.MainActivity">
//设置按钮用以启动线程
<Button
android:id="@+id/button"
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:text=“点击开始卖票” />
</RelativeLayout>
MainActivity.java
package com.example.carson_ho.demoforrunnable2;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
<span class="hljs-comment">//主布局中定义了一个按钮用以启动线程</span>
Button button;
<span class="hljs-comment">//步骤1:创建线程类,实现Runnable接口</span>
<span class="hljs-comment">//由于需要实现两个不同的操作:卖票速度1s/张和3s/张</span>
<span class="hljs-comment">//所以需要创建两个线程类并实现Runnable接口</span>
<span class="hljs-comment">//第一个线程类:实现卖票速度1s/张操作</span>
<span class="hljs-keyword">private</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyThread1</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Runnable</span></span>{
<span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> ticket = <span class="hljs-number">100</span>;<span class="hljs-comment">//一个窗口有100张票</span>
<span class="hljs-comment">//在run方法里复写需要进行的操作:卖票速度1s/张</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span></span>{
<span class="hljs-keyword">while</span> (ticket><span class="hljs-number">0</span>){
ticket--;
System.out.println(Thread.currentThread().getName() + <span class="hljs-string">"卖掉了1张票,剩余票数为:"</span>+ticket);
<span class="hljs-keyword">try</span> {
Thread.sleep(<span class="hljs-number">1000</span>);<span class="hljs-comment">//卖票速度是1s一张</span>
} <span class="hljs-keyword">catch</span> (InterruptedException e) {
e.printStackTrace();
}
}
}
}
<span class="hljs-comment">//第二个线程类:实现卖票速度3s/张操作</span>
<span class="hljs-keyword">private</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyThread2</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Runnable</span></span>{
<span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> ticket = <span class="hljs-number">100</span>;<span class="hljs-comment">//一个窗口有100张票</span>
<span class="hljs-comment">//在run方法里复写需要进行的操作:卖票速度3s/张</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span></span>{
<span class="hljs-keyword">while</span> (ticket><span class="hljs-number">0</span>){
ticket--;
System.out.println(Thread.currentThread().getName() + <span class="hljs-string">"卖掉了1张票,剩余票数为:"</span>+ticket);
<span class="hljs-keyword">try</span> {
Thread.sleep(<span class="hljs-number">3000</span>);<span class="hljs-comment">//卖票速度是3s一张</span>
} <span class="hljs-keyword">catch</span> (InterruptedException e) {
e.printStackTrace();
}
}
}
}
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(Bundle savedInstanceState)</span> </span>{
<span class="hljs-keyword">super</span>.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
<span class="hljs-comment">//Button按下时会开启一个新线程执行卖票</span>
button = (Button) findViewById(R.id.button);
button.setOnClickListener(<span class="hljs-keyword">new</span> View.OnClickListener() {
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span><span class="hljs-params">(View v)</span> </span>{
<span class="hljs-comment">//步骤2:创建线程类的实例</span>
<span class="hljs-comment">//分别实例化两个线程子类</span>
MyThread1 mt1 = <span class="hljs-keyword">new</span> MyThread1();
MyThread2 mt2 = <span class="hljs-keyword">new</span> MyThread2();
<span class="hljs-comment">//创建二个线程,模拟二个窗口卖票</span>
Thread mt11 = <span class="hljs-keyword">new</span> Thread(mt1, <span class="hljs-string">"窗口1"</span>);<span class="hljs-comment">//卖票速度1s/张</span>
Thread mt22 = <span class="hljs-keyword">new</span> Thread(mt2, <span class="hljs-string">"窗口2"</span>);<span class="hljs-comment">//卖票速度3s/张</span>
<span class="hljs-comment">//步骤3:调用start()方法开启线程</span>
<span class="hljs-comment">//启动二个线程,也即是窗口,开始卖票</span>
mt11.start();
mt22.start();
}
});
}
}
-
测试结果
由于卖票速度不同,所以窗口1卖3张时,窗口2才卖1张。
示意图
- Demo源码地址
Carson_Ho的Github地址:多线程之继承Thread类
实例3
- 应用场景:创建两个线程-实现一个耗时任务
- 实例说明:实现2个窗口同时卖火车票;两个窗口一共卖100张,卖票速度均为1s/张
建议先下载Demo再看分析:Carson_Ho的Github地址:多线程之继承Thread类
- 具体实现
main_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.carson_ho.demoforrunnable3.MainActivity">
//设置按钮用以启动线程
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击开始卖票" />
</RelativeLayout>
MainActivity.java
package com.example.carson_ho.demoforrunnable3;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
<span class="hljs-comment">//主布局中定义了一个按钮用以启动线程</span>
Button button;
<span class="hljs-comment">//步骤1:创建线程类,实现Runnable接口</span>
<span class="hljs-keyword">private</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyThread1</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Runnable</span></span>{
<span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> ticket = <span class="hljs-number">100</span>;<span class="hljs-comment">//两个窗口一共要卖100张票</span>
<span class="hljs-comment">//在run方法里复写需要进行的操作:卖票速度1s/张</span>
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span></span>{
<span class="hljs-keyword">while</span> (ticket><span class="hljs-number">0</span>){
ticket--;
System.out.println(Thread.currentThread().getName() + <span class="hljs-string">"卖掉了1张票,剩余票数为:"</span>+ticket);
<span class="hljs-keyword">try</span> {
Thread.sleep(<span class="hljs-number">1000</span>);<span class="hljs-comment">//卖票速度是1s一张</span>
} <span class="hljs-keyword">catch</span> (InterruptedException e) {
e.printStackTrace();
}
}
}
}
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(Bundle savedInstanceState)</span> </span>{
<span class="hljs-keyword">super</span>.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
<span class="hljs-comment">//Button按下时会开启一个新线程执行卖票</span>
button = (Button) findViewById(R.id.button);
button.setOnClickListener(<span class="hljs-keyword">new</span> View.OnClickListener() {
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onClick</span><span class="hljs-params">(View v)</span> </span>{
<span class="hljs-comment">//步骤2:创建线程类的实例</span>
<span class="hljs-comment">//因为是两个窗口共卖100张票,即共用资源</span>
<span class="hljs-comment">//所以只实例化一个实现了Runnable接口的类</span>
MyThread1 mt = <span class="hljs-keyword">new</span> MyThread1();
<span class="hljs-comment">//因为要创建二个线程,模拟二个窗口卖票</span>
Thread mt11 = <span class="hljs-keyword">new</span> Thread(mt, <span class="hljs-string">"窗口1"</span>);
Thread mt12 = <span class="hljs-keyword">new</span> Thread(mt, <span class="hljs-string">"窗口2"</span>);
<span class="hljs-comment">//步骤3:调用start()方法开启线程</span>
<span class="hljs-comment">//启动二个线程,也即是窗口,开始卖票</span>
mt11.start();
mt12.start();
}
});
}
}
-
测试结果
实现了两个窗口一起卖100张票的目的
结果 Demo源码地址
Carson_Ho的Github地址:多线程之继承Thread类
4. 与 “继承Thread类”对比
- 在
Java
中,继承Thread
类和实现Runnable
接口是实现多线程最常用的2种方法 - 今天我们就来对比下这两种方法
若还不熟悉 继承
Thread
类的使用,请看文章Android多线程:继承Thread类 使用解析(含实例教程)
![](http://upload-images.jianshu.io/upload_images/944365-a231c11b363f1410.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/870/format/webp)
5. 总结
- 本文主要对多线程中实现
Runnable
的用法进行了全面介绍