Java多线程的三种用法和比较
Java的三种多线程用法分别为:继承Thread、实现Runnable、实现Callable,下面会分别进行介绍
第一种继承Thread
这种方法很简单,就是继承Thread,然后重写run方法,在调用的时候用start方法就行了。
Thread类中已经实现了Runnable,使用起来相对来说更方便简洁。
//直接继承Thread,然后重写run方法
public class MyThread extends Thread{
@Override
public void run(){
System.out.println("Thread");
}
}
class Test{
public static void main(String[]args){
//1、初始化一个对象后,调用的是start方法,不是调用重写的run方法
MyThread myThread=new MyThread();
myThread.start();
}
}
第二种实现Runnable
这种方式就是直接实现Runnable,在调用的时候最终还是把Runnable传到Thread再调用Thread的start实现
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable");
}
}
class Test{
public static void main(String[]args){
//2、使用Runnable实现
Runnable runnable=new MyRunnable();
Thread thread=new Thread(runnable);
thread.start();
}
}
第三种实现Callable
使用这种方式的好处就是能得到线程的返回值和抛出的异常,这是前面两种所不具备的
class MyCallable implements Callable{
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName());
return 1;
}
}
class Test{
public static void main(String[]args){
//3、使用callable实现,使用callable的好处是有返回值
//new Thread(new FutureTask<Integer>(new MyCallable())).start();
Callable callable=new MyCallable();
int sumNumber=0;
for (int i=1 ;i<=10;i++) {
FutureTask<Integer> futureTask = new FutureTask(callable);
Thread thread1 = new Thread(futureTask, "callable"+i);
thread1.start();
try {
//得到返回值,这里会造成阻塞,意思是直到这个线程工作完后,才能进行下一步
Integer result = futureTask.get();
sumNumber+=result;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
//所有线程完后计算的结果
System.out.println(sumNumber);
}
}
三种方式的对比
第一种方式内部已经实现了Runnable,所以相对于其它两种使用起来更方便,但是因为Java的单继承属性,所以我们的类继承Thread后就不能继承其它类了
第二种方式的好处就是我们的类实现的是一个接口,所以还可以继承其它类
第三种方式相对来说比较复杂,但是它的好处就是能得到线程的返回值和抛出的异常,如果不需要得到返回值和抛出的异常,建议不使用这种方式,因为在调用futureTask.get(),也就是得到线程的返回值时是阻塞的,只有等这个线程执行完,才能执行接下来的事情
三种方式的实现和结果
package com.zhou.thread.multithread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @author zhou
* @version 1.0
* @Description
* @date 2022/3/25 10:58
*/
//直接继承Thread,然后重写run方法
public class MyThread extends Thread{
@Override
public void run(){
System.out.println("Thread");
}
}
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable");
}
}
class MyCallable implements Callable{
@Override
public Integer call() throws Exception {
System.out.println(Thread.currentThread().getName());
return 1;
}
}
class Test{
public static void main(String[]args){
//1、初始化一个对象后,调用的是start方法,不是调用重写的run方法
MyThread myThread=new MyThread();
myThread.start();
//2、使用Runnable实现
Runnable runnable=new MyRunnable();
Thread thread=new Thread(runnable);
thread.start();
//3、使用callable实现,使用callable的好处是有返回值
//new Thread(new FutureTask<Integer>(new MyCallable())).start();
Callable callable=new MyCallable();
int sumNumber=0;
for (int i=1 ;i<=10;i++) {
FutureTask<Integer> futureTask = new FutureTask(callable);
Thread thread1 = new Thread(futureTask, "callable"+i);
thread1.start();
try {
//得到返回值,这里会造成阻塞,意思是直到这个线程工作完后,才能进行下一步
Integer result = futureTask.get();
sumNumber+=result;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
//所有线程完后计算的结果
System.out.println(sumNumber);
}
}
结果