Java创建线程的四种方式
1.直接继承Thread类
/**
* 第一种方式:继承Thread,重写run方法
*/
class MyThread extends Thread{
@Override
public void run() {
for(int i = 0;i <= 1000;i++){
if(i % 2 == 0){
System.out.println(i);
}
}
}
}
// 匿名内部类的方式创建线程
new Thread(){
@Override
public void run() {
for(int i = 0;i <= 1000;i++){
if(i % 2 == 0){
System.out.println(i);
}
}
}
}.start();
2.实现Runnable的run方法
/**
* 第二种方式:实现Runnable接口,实现run方法
*/
class MyRunnable implements Runnable{
@Override
public void run() {
for(int i = 0;i <= 1000;i++){
if(i % 2 == 0){
System.out.println(i);
}
}
}
}
// 匿名内部类
new Thread(new Runnable(){
@Override
public void run() {
for(int i = 0;i <= 1000;i++){
if(i % 2 != 0){
System.out.println(i);
}
}
}
}).start();
// 使用lambda表达式
new Thread(()->{
for(int i = 0;i <= 1000;i++) {
if (i % 2 != 0) {
System.out.println("===");
}
}
}).start();
3.实现Callable接口
public interface<T> Callable{
V call() throws Exception;
}
相较于Runnable接口,Callable接口有以下的优点
- 方法有返回值,支持泛型的返回值
- 可以抛出异常
// 实现Callable接口的call方法
class MyThread implements Callable<Integer>{
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0;i < 100;i++){
sum += i;
}
return sum;
}
}
返回值的获取使用FutrueTask类
/**
* FutureTask实现了Runnable和Future接口
* 可以将Callable接口包装成Runnable接口以启动线程,
* 实现Future接口以获取返回值
*/
public class FutureTask<V> implements RunnableFuture<V>;
public interface RunnableFuture<V> extends Runnable, Future<V>;
// 将Callable接口包装成FutureTask接口
FutureTask<Integer> task = new FutureTask(new MyThread());
// task实现类Runnable接口,所以可以被run
Thread t1 = new Thread(task);
t1.start();
try {
// 使用Future接口中的get()方法获取返回值
System.out.println("sum="+task.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
4.使用线程池
线程池的引入:
- 对于需要大量的周期短的线程的任务,如果每次都去创建,又很快的销毁,无疑对于操作系统来说,负担是很大的。所以可以将一定数量的线程放入到线程池当中,需要使用线程时从线程池中取出,线程运行结束又放回到线程池当中,而不是直接销毁。
- 线程不是创建的越多越好的。可以使用线程池控制线程的数量,发挥多线程的优势
Java中对线程池提供的方法和接口
-
线程池的创建
// 执行器工具类 public class Executors{ // 该池包含固定数量的线程;空闲线程会一直被保留 public static ExecutorService newFixedThreadPool(..); // 只有一个线程的 “池”, 该线程顺序执行每一个提交的任务 public static ExecutorService newSingleThreadExecutor(..); // 必要时创建新线程;空闲线程会被保留 60 秒 public static ExecutorService newCachedThreadPool(..); // 用于预定执行而构建的固定线程池, 替代 java.util.Timer public static ScheduledExecutorService newScheduledThreadPool(..); // 用于预定执行而构建的单线程 “池” public static ScheduledExecutorService newSingleThreadScheduledExecutor(); public static ExecutorService newWorkStealingPool(..); } // ExecutorService 接口 void shutdown(); // 关闭线程池 // submit适用于Callable,有返回值 // execute适用于Runnable <T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task); void execute(Runnable command);
-
简单使用线程池
// 创建线程池 ExecutorService executorService = Executors.newCachedThreadPool(); // 将线程提交给线程池 Future<Integer> future = executorService.submit(new MyThread()); executorService.submit(new MyThread()); try { // 如果需要返回值,可以get获取 System.out.println(future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } // 关闭线程池 executorService.shutdown();