引言

本文用来指导java多线程入门。

java中创建新的线程的方式有三种:

  • 实现Runnable接口
  • 集成Thread类
  • 实现Callable接口,结合Future创建线程。

下面将分别使用这三种方式创建线程,并实现线程顺序执行。

继承关系

java子线程怎么释放 java开启子线程_java子线程怎么释放

java子线程怎么释放 java开启子线程_java_02

 

 

线程内调用其他对象的方法

        新建的线程类里可以自己自定义变量,自定义其他方法等,并且都可以在run方法里调用,所以为了方便后续的demo编写,将run方法内的内容提出来。具体代码如下

public class Execution {
    
    public static  void print(String threadName){
        for (int i=1; i<=2; i++){
            System.out.println("执行轮次:"+ i);
            System.out.println("执行线程:"+ threadName);
        }
    }
}

继承Thread类实现新建线程

        下面使用继承Thread类的方式新建一个线程类。

public class ThreadDemo extends Thread {
    String threadName;
    Thread thread;

    @Override
    public void run() {
        Execution.print(threadName);
    }

    public ThreadDemo(String threadName){
        this.threadName = threadName;
    }

    @Override
    public void start() {
        System.out.println("starting----"+threadName);
        if(thread == null){
            thread = new Thread(this,threadName);
        }
        thread.start();
    }
}

实现Runnable接口实现新建线程

public class RunnableDemo implements Runnable{

    Thread thread;
    String threadName;

    @Override
    public void run() {
        Execution.print(threadName);
    }

    public RunnableDemo(String threadName){
        this.threadName = threadName;
    }

    public void start() throws InterruptedException {
        System.out.println("starting----"+threadName);
        if(thread == null){
            thread = new Thread(this,threadName);
        }
        thread.start();
    }

}

实现Callable接口实现新建线程

public class CallableDemo implements Callable<String> {
    String threadName;

    CallableDemo(String threadName){
        this.threadName = threadName;
    }

    @Override
    public String call() throws Exception {
        System.out.println("starting----"+threadName);
        Execution.print(threadName);
        return "callable线程的返回值";
    }
}

        实现Callable接口实现线程需要结合Future来实现,在后续代码中可以看到。

实现多线程并行

        在主线程中新建多个子线程,同步执行:

public class ThreadTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        long startTime = System.currentTimeMillis();
        for(int i=1; i<=2; i++) {
            ThreadDemo threadDemo = new ThreadDemo("thread线程" + i + "号");
            threadDemo.start();
            RunnableDemo runnableDemo = new RunnableDemo("runnable线程" + i + "号");
            runnableDemo.start();
            CallableDemo callableDemo = new CallableDemo("callable线程" + i + "号");
            FutureTask<String> futureTask = new FutureTask<>(callableDemo);
            futureTask.run();
            System.out.println("-*-*-*-*-"+futureTask.get());
        }
        long endTime = System.currentTimeMillis();
        long cost = (endTime - startTime);
        System.out.println("用时" + cost +"ms");
    }
}

        执行后可以看到输出结果:

starting----thread线程1号
starting----runnable线程1号
执行轮次:1
执行线程:thread线程1号
执行轮次:2
执行线程:thread线程1号
starting----callable线程1号
执行轮次:1
执行线程:callable线程1号
执行轮次:2
执行线程:callable线程1号
-*-*-*-*-callable线程的返回值
starting----thread线程2号
starting----runnable线程2号
starting----callable线程2号
执行轮次:1
执行线程:callable线程2号
执行轮次:2
执行线程:callable线程2号
-*-*-*-*-callable线程的返回值
用时3ms
执行轮次:1
执行线程:runnable线程1号
执行轮次:2
执行线程:runnable线程1号
执行轮次:1
执行线程:thread线程2号
执行轮次:2
执行线程:thread线程2号
执行轮次:1
执行线程:runnable线程2号
执行轮次:2
执行线程:runnable线程2号

        可以看到主线程及子线程执行的先后顺序并不是固定的。要想是的线程按照新建的先后顺序来执行,要怎么实现呢,方法就是可以使用join()方法。可以看下join()方法的源码:

public final void join() throws InterruptedException {
    join(0);
}

public final synchronized void join(long millis)
throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;

    if (millis < 0) {
        throw new IllegalArgumentException("timeout value is negative");
    }

    if (millis == 0) {
        while (isAlive()) {
            wait(0);
        }
    } else {
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

        可以看到 如果不传入参数,会调用默认的join(0)方法,如果当前线程没执行完毕,子线程会一直wait。

        所以只要加入join方法即可。

public class RunnableDemo implements Runnable{

    Thread thread;
    String threadName;

    @Override
    public void run() {
        Execution.print(threadName);
    }

    public RunnableDemo(String threadName){
        this.threadName = threadName;
    }

    public void start() throws InterruptedException {
        System.out.println("starting----"+threadName);
        if(thread == null){
            thread = new Thread(this,threadName);
        }
        thread.start();
        thread.join();
    }

}
public class ThreadDemo extends Thread {
    String threadName;
    Thread thread;

    @Override
    public void run() {
        Execution.print(threadName);
    }

    public ThreadDemo(String threadName){
        this.threadName = threadName;
    }

    @Override
    public void start() {
        System.out.println("starting----"+threadName);
        if(thread == null){
            thread = new Thread(this,threadName);
        }
        thread.start();
        try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

调整之后的执行结果如下:

starting----thread线程1号
执行轮次:1
执行线程:thread线程1号
执行轮次:2
执行线程:thread线程1号
starting----runnable线程1号
执行轮次:1
执行线程:runnable线程1号
执行轮次:2
执行线程:runnable线程1号
starting----callable线程1号
执行轮次:1
执行线程:callable线程1号
执行轮次:2
执行线程:callable线程1号
-*-*-*-*-callable线程的返回值
starting----thread线程2号
执行轮次:1
执行线程:thread线程2号
执行轮次:2
执行线程:thread线程2号
starting----runnable线程2号
执行轮次:1
执行线程:runnable线程2号
执行轮次:2
执行线程:runnable线程2号
starting----callable线程2号
执行轮次:1
执行线程:callable线程2号
执行轮次:2
执行线程:callable线程2号
-*-*-*-*-callable线程的返回值
用时3ms