1.why?
在程序中如果没有主动创建,只会存在一个主线程(但是在JVM中不止一个线程,还有诸如垃圾回收等)
所以为了提升性能aka加速,java开发中通常需要创建线程
2.how?
方法一:继承Thread类并重写run()
public class TestDemo{ public static void main(String args[]) { new ThreadTest().start(); //新建一个实例并调用start()开始线程 } } class ThreadTest extends Thread{ //创建一个继承Thread的新类 static int[] i = {0,1,2,3}; @Override public void run() { //新线程的入口,本质上也是实现了runable接口 for(int x:i) { System.out.println(x); } } }
方法二:继承Runable接口并重写run()
public class TestDemo{ public static void main(String args[]) { RunnableTest r = new RunnableTest(); new Thread(r,"thread_1").start(); new Thread(r,"thread_2").start(); } } class RunnableTest implements Runnable{ static int[] i = {0,1,2,3}; @Override public void run() { for(int x:i) { System.out.println(x); } } }
方法三:
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class TestDemo{ public static void main(String args[]) { CallableTest c = new CallableTest();//创建 Callable 实现类的实例 FutureTask<Integer> f = new FutureTask<>(c); //FutureTask 类来包装Callable对象,并封装返回值 new Thread(f).start(); //使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程 try { //调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。 System.out.println("子线程的返回值: " + f.get()); //FutureTask对象的get()要配合异常捕获语句使用 } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } } class CallableTest implements Callable{ //通过继承Callable接口创建实现类 static int[] i = {0,1,2,3}; @Override public Integer call() throws Exception{ //重写的call()方法将作为线程执行体,并且有返回值 //throws Exception放在方法后边,表示的是本方法不处理异常,交给被调用处处理 int t = 0; for(int x:i) { System.out.println(x); t++; } System.out.println(Thread.currentThread().getName() + " is running"); return t; } }
3.优劣比较
直接继承Thread类并重写run方法:编写简单,访问当前线程无需使用 Thread.currentThread() 方法,直接使用 this 即可;但已经继承了Thread,就不可以继承其他父类
runnable/callable:可以实现多继承,多个线程可以共享同一个target对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU、代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想
runnable与callable的区别:
(1) Callable重写的是call(),Runnable重写的是run()。
(2) Callable的任务执行后可返回值,而Runnable不能。
(3) call方法可以抛出异常,run方法不可以。
(4) 运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果