java 多线程 runnable_java多线程(二)-Runnable和Thread

Java在顺序性语言的基础上提供了多线程的支持。Java的线程机制是抢占式的。这表示调度机制会周期的中断线程,将上下文切换到另一个线程,从而为每个线程都提供时间片。(与抢占式多线程对应的是 协作式多线程,每个子线程都自动的放弃控制,这就要求程序员需要在子线程的代码中插入某些让步语句)。

Java的多线程,最常见的是 Runnable和Thread类。

示例代码:src/thread_runnable/CountDown.java

1 public class CountDown implementsRunnable{2 protected int countDown = 5;3 private static int myId= 0;4 private final int taskId = myId++;5 publicCountDown() {6 super();7 }8

9

10 public CountDown(intcountDown) {11 super();12 this.countDown =countDown;13 }14

15 publicString status() {16 return "#" + taskId + "#(" + (countDown>0 ? countDown : "Over") + "), " +Thread.currentThread().getName();17 }18 public voidrun() {19 while(countDown-- > 0){20 System.out.println(status());21 Thread.yield();22 }23 }24

输出结果:

4cd4c570ab9b7812759e026f09f47f5b.png

通过输出可以看出来,Runnable的运行其实还是main线程。(当一个java程序运行时,默认会启动两个线程,一个main线程,一个gc线程)。

所以说,Runnable接口其实就是 描述任务的接口,要想定义某个任务,可以 实现Runnable接口并编写run()方法。

另外,代码当中的 Thread.yield() 方法是对线程调度器的一种建议。意思是“当前线程最重要的部分已经执行完毕了,可以把时间片切换给其他线程了”。当然,该方法也就是个建议而已,实际效果这个取决于具体的jvm。就像你跟领导提意见一样,建议可以提,但是领导是否采纳那就另一说了。因为java的线程机制是抢占式机制。

而实际上,真正实现启动新线程的是 Thread类,

示例代码:src/thread_runnable/DirectThread.java

1 public class DirectThread extendsThread{2 protected int countDown = 5;3

4 publicString status() {5 return "###(" + (countDown>0 ? countDown : "Over") + "), " +Thread.currentThread().getName();6 }7 @Override8 public voidrun() {9 //TODO Auto-generated method stub

10 while(countDown-- > 0){11 System.out.println(status());12 }13 }14

15 public static voidmain(String[] args) {16 System.out.println("DirectThread --- main start, " +Thread.currentThread().getName());17 newDirectThread().start();18 System.out.println("DirectThread --- main end, " +Thread.currentThread().getName());19 }20 }

输出结果:

081270e53d524d19a8b0738f746065a0.png

通过代码和输出结果,我们可以观察到Thread类,的确启动了一个新线程,并且可以看到main函数方法最后一条语句执行完,才开始输出Thread类中 run()方法当中的内容。这个run()方法就是新线程需要执行的任务。

不过在实际当中,我们经常并不是单独使用Thread类,而是在Thread类的构造器中传递类一个 Runnable()对象。然后调用Thread对象的start()方法来为该线程执行必须的初始化操作。然后系统会自动调用Runnable的run()方法。

示例代码:src/thread_runnable/ThreadRunnable.java

1 public classThreadRunnable{2

3 private static final String TAG = "LiftOff";4

5 public static voidmain(String[] args) {6 //TODO Auto-generated method stub

7

8 System.out.println("main start, " +Thread.currentThread().getName());9 for (int i=0; i<3; i++){10 Thread thread = new Thread(newCountDown());11 thread.start();12 }13 System.out.println("main end, " +Thread.currentThread().getName());14 }15

16 }

输出结果: (每次执行的结果都有差别)

1266a6d1793e2a849845d904d9caef20.png

可以看出,新启动了三个新线程,来输出各自的任务,并且从结果,还可以看出,三个线程的执行顺序都是随机的,并且每次执行的结果都不同。那么这就说明线程运行的时候是被混在一起的,这种线程的切换就是线程调度器来进行自动控制的。具有不确定性。而对于多核处理器,也有可能在几个不同的核上同时执行着几个线程,但是对于输出信息到控制台,(就是 System.out.println()语句),这种输出资源是只存在一份的。

既然可以直接使用Thread()对象的start()方法来启动新线程,那为什么还要使用Runnable()对象来传递到Thread()对象的构造方法中,在Runnable对象的run()方法中来执行任务呢。原因如下:

(1)java是单根继承,而Runnable是interface。方便了任务的继承。

(2)解耦,任务本身与线程分离,两者相互独立。也方便任务代码被多个线程共享。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值