引言
本文用来指导java多线程入门。
java中创建新的线程的方式有三种:
- 实现Runnable接口
- 集成Thread类
- 实现Callable接口,结合Future创建线程。
下面将分别使用这三种方式创建线程,并实现线程顺序执行。
继承关系
线程内调用其他对象的方法
新建的线程类里可以自己自定义变量,自定义其他方法等,并且都可以在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