您的位置:首页 > 移动开发 > Android开发

Android初学之Runnable和Thread

2016-07-27 15:12 543 查看
Runnable代表了一条能被执行的命令,经常用在不同的线程里去执行一段代码的接口。其中只有一个方法:void run(),该方法用于执行相关的业务代码,当实现了Runnable接口的类创建了一个线程并启动了该线程(即使用了void start()方法)时,会调用run方法。

Runnable的使用:

1、 实现Runables接口外部类:

public class MainActivity extends AppCompatActivity {

public class MyThread implements Runnable{

@Override
public void run() {
for(int i=0;i<10;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("这是一个实现了Runnable的线程");
}
}
}
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

@Override
protected void onResume() {
super.onResume();
MyThread myThread = new MyThread();
//        Thread thread = new Thread(myThread);
//        thread.start();
myThread.run();
for(int i=0;i<10;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("这是主线程");
}
}
}


很容易能够看出上述代码的缺点:MyThread中的方法只是用了一次,但是却以一个外部类的形式描述,显然是不合理的,因此可以在匿名内部类表述出来。匿名内部类一般用于只执行一次的情况下使用,减少代码量,而外部类主要适用于需要多次重复使用的情况。

2、匿名内部类

ackage com.zhouyou.robocademoproj;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

@Override
protected void onResume() {
super.onResume();
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0;i<8;i++){
System.out.println("这是匿名内部类的使用");
}
}
};
Thread thread = new Thread(runnable);
thread.start();

for(int i = 0;i<8;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("这是主线程的使用");
}
}
}


3、Runnable的一些理解:

我们暂且抛开匿名内部类和外部类的区别,看一下上述代码的输出结果发现,两个线程的输出是交替出现的,且两个线程id是不同的。



所以,我们就好理解为什么API中说它是运行在一个不同的线程里了。

4、 如果直接调用Runnable的run方法会出现什么情况呢?

package com.zhouyou.robocademoproj;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

@Override
protected void onResume() {
super.onResume();
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0;i<8;i++){
System.out.println("这是匿名内部类的使用");
}
}
};
runnable.run();
//直接调用run方法,不使用Thread的start
//        Thread thread = new Thread(runnable);
//        thread.start();

for(int i = 0;i<8;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("这是主线程的使用");
}
}
}


运行的输出结果如下:



因为次数只有10次,为保证正确性,我实验了n次,发现都是上述结果。

上图中,线程id是一样的,也就是说根本没有新开一个线程去运行Runnable相关的代码,而是直接在主线程运行的,说明了一点:直接调用run方法,不经过start并不能实现多线程,也就是像Runnable源码中解释的那样,Runnable只是一个代表了一条能被执行的命令,经常用在不同的线程里去执行一段代码的接口,注意它是用在线程里,而不是自身就能直接多线程。

我们再看看Thread中的start方法:

/**
* Starts the new Thread of execution. The <code>run()</code> method of
* the receiver will be called by the receiver Thread itself (and not the
* Thread calling <code>start()</code>).
*
* @throws IllegalThreadStateException - if this thread has already started.
* @see Thread#run
*/
public synchronized void start() {
checkNotStarted();

hasBeenStarted = true;

nativeCreate(this, stackSize, daemon);
}


start方法完成了实现多线程的初始化操作,run方法中完成了业务操作(一般是编程者自己写的业务实现代码)。至于如何实现的,则不是我们需要关心的。

Thread是一个执行并发的单元,他有自己的方法调用栈,参数栈和本地变量的栈。每一个应用开始后,在主线程组中至少有一个运行着的主线程。Thread本质上来说他是一个实现了Runnable接口的类,他在Runnable的基础上添加了一些能够保证多线程运行的机制。一般来说有两种方法在新线程中执行业务代码:

1、继承了Thread并重写了run方法的Thread子类。

2、将一个实现了Runnable接口的实例作为Thread的构造参数(Runnable中的demo就是这么做的)。

除了大量的构造函数,还有一些基本成员属性,比如name、priority、stackSize、packState等,这些属性都是为了更好的实现多线程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息