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)缺点:编写复杂,要考虑的因数较多