likes
comments
collection
share

java线程总结(1)-Thread和Runnable的区别

作者站长头像
站长
· 阅读数 16

一、线程和进程的区别

  • 进程:进程是资源分配的基本单位,计算机将某个资源,比如内存中的某块区域划分给某个进程,该进程独占此项资源,其他进程无法访问。
  • 线程:线程是cpu调度的基本单位,cpu通过时间片轮转法,在固定时间片内执行某个线程。一个进程内可以有一到多个线程,分别代表程序的不同的执行路线,同一个进程内的不同线程共享同一块内存资源。

二、如何开启一个线程

2.1 Thread/Runnable

2.1.1 Thread

new Thread() {
    @Override
    public void run() {
        log("Thread run");
    }
}.start();

输出:

Thread run

2.1.2 通过Runnable

new Thread(new Runnable() {
    @Override
    public void run() {
        log("Runnable run");
    }
}).start();

输出:

Runnable run

2.1.3 Thread和Runnable的区别

首先看一下Runnable这个接口的结构

public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

可以看到其结构极其简单,里面只有一个抽象方法run()。 再看一下Thread的start()方法

/**
 * Causes this thread to begin execution; 
 * the Java Virtual Machine calls the run method of this thread.
 * ...
 */
public synchronized void start() {
    ...
}

start()方法的内容对于我们来说不是很重要,重要的是第一句注释,开启线程,run()方法会在线程开始执行后被java虚拟机调用,那么接下来看一下Thread的run()方法

@Override
public void run() {
    if (target != null) {
        target.run();
    }
}

Thread的run方法仅仅做了一个判空,如果target不为空,就调用target的run方法,那么这个target是什么呢。

public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

可以看到这个target就是我们在Thread的构造方法中传入的Runnable,也就是我们在 2.1.2节 开启线程的方式。

总结

  1. Runnable接口只是一个具有抽象方法 run() 的普通接口
  2. Thread 的run方法会在线程调用start后,在某一时刻被虚拟机调用,若Thread中持有的类型为Runnable的target变量不为空,则会调用target的run方法。 思考

我们是否可以既重写了Thread的run方法,又使用runnable呢?理论上是可以的,我们来试一下

public static void testThreadRunnable() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            log("Runnable run");
        }
    }) {
        @Override
        public void run() {
            super.run();
            log("Thread run");
        }
    }.start();
}

输出

Runnable run
Thread run

可以看到实际上也是可以的,需要注意的是,我们重写的Thread的run方法需要调用 “super.run()”,只有这样Runnable里的run方法才会被调用。