java多线程--线程的3种实现方式及线程池

it2022-05-05  172

1、继承Thread

Thread类本身实现了  Runnable 接口。  从某个角度Thread类可以看成是Runnable的包装类

如果需要在线程开启时携带参数,使用在线程类使用构造函数来实现

public class ThreadDemo1 { public static void main(String[] args) { Thread thread1 = new ThreadDemo(); Thread thread2 = new ThreadDemo(); //开启一个新线程调用start() 如果是调用run()方法则不会开启新线程,而是用主线程执行 thread1.start(); thread2.start(); } } class ThreadDemo extends Thread{ public void run(){ System.out.println("这个线程在疯狂的跑"); } }

使用匿名内部类实现

new Thread(){ public void run(){ System.out.println("在方法内开启了新线程"); } }.start();

2、实现Runnable接口

和继承Thread类实现基本一致,不过是我们自行实现了Runnable接口,然后再用Thread包装。

因java不支持多继承,在类已经存在继承的情况下,可以使用这种方式

public class ThreadDemo2 { public static void main(String[] args) { Thread thread1 = new Thread(new RunnableImpl()); Thread thread2 = new Thread(new RunnableImpl()); thread1.start(); thread2.start(); } } class RunnableImpl implements Runnable{ @Override public void run() { System.out.println("这个线程也在疯狂的跑"); } }

匿名内部类实现

new Thread(new Runnable(){ @Override public void run() { System.out.println("用匿名内部类和Runnable启动了一个新线程"); } }).start();

3、实现Callable接口

实现Callable接口的线程,可获取返回值

使用FutureTask  get()方法获取返回值,get()方法是阻塞的,会一直阻塞主线程等待返回结果。

public class ThreadDemo3 { public static void main(String[] args) throws InterruptedException, ExecutionException { CallableImpl callable1 = new CallableImpl("标记xxx"); FutureTask<String> futhre = new FutureTask<String>(callable1); Thread thread1 = new Thread(futhre); thread1.start(); String res = futhre.get(); System.out.println("测试futhre.get是不是阻塞的"); System.out.println(res); } } /**Callable 是个泛型类,可以指定返回参数的类型, 这里把其指定为String**/ class CallableImpl implements Callable<String>{ private String reqStr; //重载了一个构造方法,这样我们在线程创建时,还能带入参数 public CallableImpl(String str){ reqStr = str; } public CallableImpl(){ }; @Override public String call() throws Exception { System.out.println("线程在运行,其标记为"+reqStr); //do something 线程执行,然后可返回一个对象 Thread.sleep(2000); String resStr = reqStr+"跑完了,并返回了这个信息"; return resStr; } }

 

4、线程池 与 Callable

使用ExecutorService管理线程池。

如不需要返回值,可将代码种的Callable 实现换乘 Runnable实现即可

线程池关闭后,不能再往其内添加新线程,但已加入到池中的线程会继续执行完

 

package a.caixl.thread; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class ThreadDemo4 { public static void main(String[] args) throws InterruptedException, ExecutionException { /**开一个线程池,并设定其线程数**/ int poolSize = 5; ExecutorService pool = Executors.newFixedThreadPool(poolSize); List<Future<String>> list = new ArrayList<Future<String>>(); for(int i=0;i<20;i++){ CallableImpl2 callable = new CallableImpl2(i+""); Future<String> future = pool.submit(callable); //将callable放入池内等待执行,submit不是阻塞方法 //future.get(); //如果再这get会阻塞主线程,那线程池就没有意义。 因此保存起来之后统一执行 list.add(future); } pool.shutdown(); //关闭后,不可再往池内submit , 但已在池内的线程会继续执行完 /**获取返回值**/ for(Future<String> future : list){ System.out.println(future.get()); } } } /**Callable 是个泛型类,可以指定返回参数的类型, 这里把其指定为String**/ class CallableImpl2 implements Callable<String>{ private String reqStr; //重载了一个构造方法,这样我们在线程创建时,还能带入参数 public CallableImpl2(String str){ reqStr = str; } public CallableImpl2(){ }; @Override public String call() throws Exception { System.out.println("线程在运行,其标记为"+reqStr); //do something 线程执行,然后可返回一个对象 Thread.sleep(2000); String resStr = reqStr+"跑完了,并返回了这个信息"; return resStr; } }

 


最新回复(0)