Java多线程 之 Runnable Thread (一)

最近看的东西有些乱。励志从XOA2看起、学起,发现需要看下thrift,看着看着thrift,发现需要学学NIO,学完了NIO温习温习前面看的thrift,却要休假10天。休假回来,感觉要学学多线程。多线程这厮,看《Thinking in java》第21章的前几个小节,这是第3次了。这次要坚持下来,并且记录下来。——勉之!
程序做的事情可以抽象成一个一个“任务”,任务是由线程来驱动的,线程是一个进程中单一的顺序控制流。在java中用什么来定义任务呢?

1.Runnable

在java中可以通过实现Runnable接口来定义一个任务。如:

package org.fan.learn.thread.task;
/**
 * Created by fan on 16-5-25.
 */
public class LiftOff implements Runnable {
    private static int taskCunnt = 0;
    private final int id = taskCunnt++;
    private int countDown = 10;
    private void status() {
        System.out.print("Task(" + id + ")#" + (countDown > 0 ? countDown : "liftOff") + "   ");
    }
    public void run() {
        while (countDown-- > 0) {
            status();
            Thread.yield();
        }
    }
}
package org.fan.learn.thread.simple;
import org.fan.learn.thread.task.LiftOff;
/**
 * Created by fan on 16-5-31.
 */
public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            new LiftOff().run();
        }

    }
}

程序的执行结果如下所示:
Task(0)#9 Task(0)#8 Task(0)#7 Task(0)#6 Task(0)#5 Task(0)#4 Task(0)#3 Task(0)#2 Task(0)#1 Task(0)#liftOff Task(1)#9 Task(1)#8 Task(1)#7 Task(1)#6 Task(1)#5 Task(1)#4 Task(1)#3 Task(1)#2 Task(1)#1 Task(1)#liftOff Task(2)#9 Task(2)#8 Task(2)#7 Task(2)#6 Task(2)#5 Task(2)#4 Task(2)#3 Task(2)#2 Task(2)#1 Task(2)#liftOff Task(3)#9 Task(3)#8 Task(3)#7 Task(3)#6 Task(3)#5 Task(3)#4 Task(3)#3 Task(3)#2 Task(3)#1 Task(3)#liftOff Task(4)#9 Task(4)#8 Task(4)#7 Task(4)#6 Task(4)#5 Task(4)#4 Task(4)#3 Task(4)#2 Task(4)#1 Task(4)#liftOff
这里直接调用了Runnable接口的run方法。注意这个run方法是没有任何返回值的。因此无法直到任务执行的状态返回值。但是驱动任务时很少这么写,一般都是由线程来驱动任务。

Thread

package org.fan.learn.thread.simple;
import org.fan.learn.thread.task.LiftOff;
/**
 * Created by fan on 16-5-31.
 */
public class Main2 {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            new Thread(new LiftOff()).start();
        }
        System.out.println("Waiting for liftOff!");
    }
}

程序执行结果如下所示:
Task(0)#9 Task(1)#9 Task(0)#8 Task(1)#8 Task(0)#7 Task(1)#7 Task(0)#6 Task(1)#6 Task(0)#5 Task(1)#5 Task(0)#4 Task(1)#4 Task(0)#3 Task(1)#3 Task(0)#2 Task(1)#2 Task(0)#1 Task(1)#1 Task(0)#liftOff Task(1)#liftOff Task(2)#9 Task(2)#8 Waiting for liftOff!
Task(2)#7 Task(3)#9 Task(2)#6 Task(3)#8 Task(2)#5 Task(3)#7 Task(4)#9 Task(3)#6 Task(2)#4 Task(3)#5 Task(4)#8 Task(3)#4 Task(2)#3 Task(3)#3 Task(4)#7 Task(3)#2 Task(2)#2 Task(3)#1 Task(4)#6 Task(3)#liftOff Task(2)#1 Task(4)#5 Task(2)#liftOff Task(4)#4 Task(4)#3 Task(4)#2 Task(4)#1 Task(4)#liftOff
Process finished with exit code 0

注意
(1)上面调用的是Thread.start()。start方法会为线程的执行做一些准备工作,然后调用Runnable接口的run方法。
(2)可以看到main中先输出了“Waiting for liftOff”方法,后面还有线程在执行。说明在main中执行完输出退出程序时,new出的Thread对象依然还在内存中,没有被垃圾回收,依然可以继续执行,直到其run方法执行完。其实,每个Thread“注册”了自己,因此JVM中确实有一个对它的引用,所以在main退出后,没有被垃圾回收。Thread对象有别于普通对象。

run与start的区别

run方法不会启动新的线程,在调用run方法的线程中运行。
而start方法会new出一个新线程,在这个新线程中执行。
这也就是为什么需要区分“线程”和“任务”这两个概念。线程是为了驱动任务的。可以这么说,任务是一个静态的概念,而线程是一个动态的概念。
下面有个例子(该例子来自网络):

// Demo.java 的源码
class MyThread extends Thread{  
    public MyThread(String name) {
        super(name);
    }

    public void run(){
        System.out.println(Thread.currentThread().getName()+" is running");
    } 
}; 

public class Demo {  
    public static void main(String[] args) {  
        Thread mythread=new MyThread("mythread");

        System.out.println(Thread.currentThread().getName()+" call mythread.run()");
        mythread.run();

        System.out.println(Thread.currentThread().getName()+" call mythread.start()");
        mythread.start();
    }  
}

运行结果:

main call mythread.run()
main is running
main call mythread.start()
mythread is running

(01) Thread.currentThread().getName()是用于获取“当前线程”的名字。当前线程是指正在cpu中调度执行的线程。
(02) mythread.run()是在“主线程main”中调用的,该run()方法直接运行在“主线程main”上。
(03) mythread.start()会启动“线程mythread”,“线程mythread”启动之后,会调用run()方法;此时的run()方法是运行在“线程mythread”上。

你可能感兴趣的:(java)