前言

广义上讲,JAVA实现多线程有三种方式:继承Thread类、实现Runnable接口、实现Callable接口利用FutureTask类,本质上来说,最终都要通过 new Thread(…).start();来实现,也就是说最终的多线程还是由Thread类来实现的,那么其它两种方式出现的目的是什么呢?因为Thread继承的直接方式具有一定的局限性,另外两种方式在Thread的基础上利用优秀的设计模式(装饰器、适配器模式)对Thread进行了功能扩展**

/**
*构造方法,  这里并没有 Callable 或者 FutureTask参数,那么Thread是怎么实现第三种方式的呢,下面再细说
*/
public Thread(String name) {
        init(null, null, name, 0);
    }
public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

Thread

public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }

    public class MyThread extends Thread{
        @Override
        public void run() {
            //本身就是Thread类型对象,所以可以直接调用Thread提供的方法
            this.currentThread();
            System.out.println("这是继承自Thread类的子类创建的线程, 线程名字: " + this.currentThread().getName());
        }
    }

源码:最终会调用一个 start0 的本地方法来创建多线程(start0方法的具体实现是JVM源码 C、Cpp代码实现一系列多线程操作,这里不做阐述)start方法是真正意义的启动多线程,多线程启动后,会回调run方法执行用户自己的逻辑,这个具体调用,什么时候调用也是JVM源码去做的,另外 Thread 继承Runnable接口,重写了run方法,如果我们是用的Thread的子类来执行多线程,因为子类也重写了该方法,那么就会回调子类的run方法

public class Thread implements Runnable {
	public synchronized void start() {
	//start真正执行多线程的方法
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        boolean started = false;
        try {
            start0();  //最终是调用了一个start0来执行多线程
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
	}
	
	private native void start0();

	/**
	* 重写父类run方法,start开启一个线程后会回调该方法
	*/
	    @Override
    public void run() {
   		//...因为继承Thread的子类重写了该方法,这里具体的源码部分不做展示
    }
  }

Runnable接口

第2种方式是实现Runnable接口,Runnable接口只是提供了一个run方法,没有具体实现,我们可以在run方法里面执行自己的逻辑,

public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        new Thread(myRunnable).start();
    }

    public class MyRunnable implements Runnable{
        public void run() {
            System.out.println("这是实现Runnable接口的实现类创建的线程, 线程名字: " + Thread.currentThread().getName());
        }
    }

(1)既然最终还是执行的Thread中的方法调用,那么为什么还要用Runnable接口呢,有什么好处呢?
Thread是类,JAVA是单继承,如果继承了Thread类就不再能扩展了,不利于程序设计,所以又提供了一个Runnable接口
(2)Runable接口是如何和Thread关联起来的呢
在上面Thread源码中我们看到 Thread继承了Runnable,重写了run方法,而且上面我们知道,strat()成功开启一个线程后,JVM会回调run方法,那么就会执行run里面的逻辑
(3)这里其实用到了装饰器模式,装饰器 Thread 和被装饰的类 Runnable子类都实现了Runnable接口,重写同一个方法,Runnable实现类作为属性注入到装饰器中,装饰器调用该方法,最终调用注入的Runnable接口的该方法

/**
	* Thread 继承了Runnable接口 重写父类run方法,start开启一个线程后会回调该方法,执行里面的逻辑,这个target其实就是
	* 一个Runnable实现类(多态),
	*/
public class Thread implements Runnable {
    /* What will be run. */
    private Runnable target;	

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

FutureTask、Callable

Runnable接口解决了单继承了问题,提供了良好的扩展性,但是问题又来了,不管Thread、还是Runnable,都存在一些问题
(1)线程一旦启动就不能停止了
(2)都没有返回值,如果我们想要执行一个有返回值的线程,就要自己实现返回值的获取(可以使用共享变量)

public static void main(String[] args) {
		MyCallable myCallable = new MyCallable();
        FutureTask<String> futureTask = new FutureTask<String>(myCallable);
        new Thread(futureTask).start();
        String s = null;
        try {
            // FutureTask的get()方法和主线程是同步的,因为想要获得Callable线程的返回值,就必须等到Callable线程执行结束
            s = futureTask.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("Callable方式的返回值: " + s);
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    public class MyCallable implements Callable<String>{

        public String call() throws Exception {
            try {
                Thread.sleep(1000 * 60);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("这是实现Callable接口的FutureTask方式创建的线程,线程名字: " + Thread.currentThread());
            return "hello";
        }
    }

(1)最终执行多线程都是由,Thread提供的start方法来执行,那么,Futuretask、Callable是如果实现的多线程呢?,xia’m 源码我们只摘出来其中一部分,因为FutureTask实现了RunnableFuture , RunnableFuture 又继承了Runnable接口,所以,Thread构造方法中我们就可以传递Runnable接口的子类FutureTask,最终调FutureTask用子类重写RunnableFuture 的run方法,而在FutureTask的run方法中,我们最终又调用了属性Callable的call方法,最终实现多线程
(2)在FutureTask的run方法中,除了执行属性Callable的run方法,我们还做了进一步扩展,比如当call方法执行完毕后初始化result返回值属性,从而得到返回值
(3)设计模式——>适配器模式,这里是Callable接口和Runnable接口,本身无关联,通过Runnable接口的实现类的run方法中调用call方法,最终实现关联,这是典型的适配器模式,把Callable call接口和Runnable run接口进行适配并做扩展,Future就相当于一个适配器,

public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}

public class FutureTask<V> implements RunnableFuture<V> {
	private Callable<V> callable;

   /**
   *构造方法
   */
   public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
    
    /**
    最终执行
    */
	public void run() {
		if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        	}
    	}
	}
}

FutureTask 获取返回值 get()方法

由上面实现我们知道,在run方法中进行返回值result的初始化,但是run方法是多线程开启后回调的,是异步的,get方法是同步的,每次调用**get()**方法时候,多线程可能还没有执行完毕,FutureTask 通过自旋的方式,不断的查询(其实最多循环三次,就进入了阻塞等待唤醒)所开启的线程的状态,是否执行完毕,执行完毕才把result返回

这里用到了自旋 + 阻塞的方式,根据操作系统中对线程状态的定义,自旋的线程一直处于用户态,阻塞切换到内核态,需要上下文切换,性能损耗比较大,但是如果自旋的时间比较长,就会长时间占用cpu而不释放,浪费cpu资源

也就是说,如果一直使用循环,不断的判断线程的状态的话,循环次数多,那么长时间的自旋就会导致cpu资源浪费,而如果直接使用阻塞的方式等待唤醒,可能线程一开启就因为某些原因挂了,线程都没怎么执行,挂了后还要唤醒,上下文切换性能损耗相对就比较大了,所以这里使用了自旋 + 阻塞的方式

**awaitDone()方法内部有一个无限循环,看似有很多判断,比较难理解,其实这个循环最多循环3次。
假设Thread A执行了get()获取计算任务执行结果,但是子任务还没有执行完,而且Thread A没有被中断,它会进行以下步骤。
step1:Thread A执行了awaitDone(),1,2两次判断都不成立,Thread A判断q=null,会创建一个WaitNode节点q,然后进入第二次循环。
step2:第二次循环,判断4不成立,此时将step1创建的节点q加入队列头。
step3:第三次循环,判断是否设置了超时时间,如果设置了超时时间,就阻塞特定时间,否则,一直阻塞,等待被其他线程唤醒。
**

public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
        return report(s);
    }
private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        WaitNode q = null;
        boolean queued = false;
        for (;;) {
            if (Thread.interrupted()) {
                removeWaiter(q);
                throw new InterruptedException();
            }

            int s = state;
            if (s > COMPLETING) {
                if (q != null)
                    q.thread = null;
                return s;
            }
            else if (s == COMPLETING) // cannot time out yet
                Thread.yield();
            else if (q == null)
                q = new WaitNode();
            else if (!queued)
                queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                     q.next = waiters, q);
            else if (timed) {
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L) {
                    removeWaiter(q);
                    return state;
                }
                LockSupport.parkNanos(this, nanos);  //阻塞
            }
            else
                LockSupport.park(this);  //阻塞
        }
    }

扩展——LockSupport

LockSupport 是一个阻塞工具类,提供了线程的阻塞和唤醒方法,所有方法都是静态的,有兴趣可以自己了解下…