Java 线程的创建方式

2022-02-28 18:16:02
一、继承Thread类,重写run()方法,实例化对象后调用start()方法 ```java public class Demo { public static void main(String[] args) { class Foo extends Thread { @Override public void run() { System.out.println("hello"); } } Foo foo = new Foo(); foo.start(); } } ``` 二、实现 Runnable 接口,实现run() 方法。Thread类的构造方法可以接收一个实现了Runnable接口的对象 ```java public class Demo { public static void main(String[] args) { class Foo implements Runnable { @Override public void run() { System.out.println("hello"); } } Foo foo = new Foo(); Thread thread = new Thread(foo); thread.start(); } } ``` 三、实现Callable接口实现call方法,配合FutureTask,能获取到线程中返回的值 ```java import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; public class Demo { public static void main(String[] args) { class Foo implements Callable<String> { @Override public String call() throws Exception { System.out.println("hello"); return "hi"; } } Foo foo = new Foo(); FutureTask<String> futureTask = new FutureTask<>(foo); Thread thread = new Thread(futureTask); thread.start(); try { String res = futureTask.get(); System.out.println(res); } catch (Exception e) { e.printStackTrace(); } } } ``` 四、线程池 ```java import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class Demo { public static void main(String[] args) { ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor( 3, //corePoolSize 核心线程池大小 5, //maximumPoolSize 线程池最大数量 (如果使用了无界的任务队列这个参数就没什么效果) 30, //keepAliveTime 空闲存活的时间 TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5), // 任务队列(阻塞队列) new ThreadPoolExecutor.AbortPolicy()); //饱和策略 poolExecutor.execute(new Runnable() { @Override public void run() { System.out.println("hello"); } }); } } ``` 比较 1、继承Thread类方式: (1)优点:编写简单,任务类中访问当前线程时,可以直接使用this关键字。 (2)缺点:任务类即线程类已经继承了Thread类,所以不能再继承其他父类。 2、实现Runnable接口的方式: (1)优点:任务类只实现了Runnable接口,还可以继承其他类。这种方式,可以多个线程对象共享一个任务类对象,即多线程共享一份资源的情况,如下: ```java TestThread tt1 = new TestThread(); Thread t1 = new Thread(tt1); Thread t2 = new Thread(tt1); t1.start(); t2.start(); ``` (2)缺点:编写稍微复杂,任务类中访问当前线程时,必须使用Thread.currentThread()方法。 3、通过Callable和Future的方式: (1)优点:任务类只实现了Callable接口,还可以继承其他类,同样多线程下可共享同一份资源,这种方式还有返回值,并且可以抛出返回值的异常。 (2)缺点:编写稍微复杂,任务类中访问当前线程时,必须使用Thread.currentThread()方法。 3、线程池方式: (1)优点:避免每次都创建和销毁线程的开销 (2)缺点:编写复杂,要考虑的因数较多