大话Android多线程(一) Thread和Runnable的联系和区别

时间:2021-12-01 17:34:55

转载自: 大话Android多线程(一) Thread和Runnable的联系和区别

前言

这是Android多线程篇的第一章,我们就从线程的创建聊起吧。常用的线程创建方式有两种(实现Callable接口的方式,我们放到以后介绍Executor框架的时候再叙)

  • 继承Thread类,重写Threadrun()方法
  • 实现Runnable接口,重写Runnablerun()方法,并将其作为参数实例化Thread

我们本章的主题正是通过比对上述两种方式创建的线程在执行任务时的差别,来理解ThreadRunnable的联系和区别

先说结论:

  • 两者的联系
    1、Thread类实现了Runnable接口
    2、都需要重写里面run()方法
  • 两者的区别
    1、实现Runnable的类更具有健壮性,避免了单继承的局限
    2、Runnable更容易实现资源共享,能多个线程同时处理一个资源

Thread和Runnable的比较

我们就以经典的卖票系统讲个故事吧。话说有小T(Thread)和小R(Runnable)两个票贩子,手下各有两个业务员,平常就干着倒卖活动门票的活(线程执行任务)。有一天,他们各拿到了5张某演唱会的门票,两人将售票的任务交给手下的业务员

小T这边的业务是这样运转的(定义Thread类的子类,重写run()方法,run()方法即为卖票任务)

public class TicketThread extends Thread {
private int ticket = 5;
private String name;

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TicketThread</span><span class="hljs-params">(String name)</span> </span>{    <span class="hljs-keyword">this</span>.name = name;}<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">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">5</span>; i++) {        <span class="hljs-keyword">if</span> (ticket &gt; <span class="hljs-number">0</span>) {            Log.e(<span class="hljs-string">"T公司"</span>,name + <span class="hljs-string">"卖了一张票,编号为t"</span> + (ticket--));        }    }}

}

业务员一大早就开始卖票,很快就卖完了(实例化Thread的子类,调用start()方法启动该线程)

TicketThread t1 = new TicketThread("1号业务员");
TicketThread t2 = new TicketThread("2号业务员");

t1.start();
t2.start();

大话Android多线程(一) Thread和Runnable的联系和区别

而小R的业务流程则是这样的(实现Runnable接口,重写Runnablerun()方法)

public class TicketRunnable implements Runnable {
private int ticket = 5;

<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">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">5</span>; i++) {        <span class="hljs-keyword">if</span> (ticket &gt; <span class="hljs-number">0</span>) {            Log.e(<span class="hljs-string">"R公司"</span>,Thread.currentThread().getName() + <span class="hljs-string">"卖了一张票,编号为r"</span> + (ticket--));        }    }}

}

业务员同样很快就把票卖完了(创建Thread子类的实例,将实现了Runnable接口的对象作为参数实例化Thread对象,调用start()方法启动线程)


TicketRunnable runnable = new TicketRunnable(); 
Thread r1 = new Thread(runnable, "1号业务员");
Thread r2 = new Thread(runnable, "2号业务员");

r1.start();
r2.start();

大话Android多线程(一) Thread和Runnable的联系和区别

事毕,两人决定吃个饭庆祝一下。一番交流后,小R很惊讶小T为啥可以将同样的票多卖一倍的钱,小T得意地安利了自己的卖票心得:

“因为我将票复印了一份,这样我两个小弟就可以各拿一份票去兜售了(通过继承Thread的方式,当新创建一个线程启动时,其绑定的任务同样也新建了一份,这样他们的任务是相互独立的,自然也无法实现资源共享了)”

小R听后感叹不已:

“竟然还有这种操作?我耿直地将票交给两个业务员就算了啊(实现Runnable接口的方式,因为都是用同一个Runnable对象创建的线程,因此多线程实际上执行的是同一个任务,这样也就共享了资源)”

接着小R又问小T:“你这么干,事后不怕买到假票的人来找你?” 小T听后不以为然道:

“怕啥,我们不都是干完一票就跑路的么(线程执行完run()方法后会自行销毁)”

小R:“我从未见过有如此厚颜无耻之人……”

(未完待续…)


下章预告

由于小R诚信经营,生意越做越大,但最近他却收到了一些投诉,有顾客说他们买到了假票。小R怀疑是自己手下干的,遂决定招个人监督自己的手下。这天,一个自称synchronized的男人前来应聘…