java入门学习:多线程创建-Thread,Runnable,callable和threadpool
来源:互联网 发布:爱奇艺格式转换器 mac 编辑:程序博客网 时间:2023/12/03 08:07
java创建多线程的方式有许多种,这里简要做个梳理
1. 继承Thread类
继承java.lang.Thread类,创建本地多线程的类,重载run()方法,调用Thread的方法启动线程。示例代码如下:
MyThread.java
public class MyThread extends Thread { public void run(){ private int copy = 0; System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis()); System.out.println("Thread serialnum:" + ++copy); try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis()); } public static void main(String[] args){ MyThread mt1 = new MyThread(); MyThread mt2 = new MyThread(); MyThread mt3 = new MyThread(); System.out.println("Start all Threads:"); mt1.start(); mt2.start(); mt3.start(); }}
输出结果:
Start all Threads:Thread id:Thread-0 == print time:1495975884383Thread serialnum:1Thread id:Thread-1 == print time:1495975884383Thread serialnum:1Thread id:Thread-2 == print time:1495975884383Thread serialnum:1Thread id:Thread-1 == print time:1495975885385Thread id:Thread-0 == print time:1495975885385Thread id:Thread-2 == print time:1495975885385
2. 实现Runnable接口
实现java.lang.Runnable接口的run方法,使用实现的对象实例化Thread类,调用Thread对象的start()方法。
示例代码:
public class MyRunnable implements Runnable { private int copy = 0; public void run(){ System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis()); System.out.println("Thread serialnum:" + ++copy); try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread id:" + Thread.currentThread().getName()+" == print time:" + System.currentTimeMillis()); } public static void main(String[] args){ MyRunnable mr = new MyRunnable(); System.out.println("Start all Threads:"); new Thread(mr).start(); new Thread(mr).start(); new Thread(mr).start(); }}
输出结果:
Start all Threads:Thread id:Thread-0 == print time:1495975833588Thread id:Thread-1 == print time:1495975833588Thread serial:1Thread id:Thread-2 == print time:1495975833588Thread serial:2Thread serial:3Thread id:Thread-0 == print time:1495975834603Thread id:Thread-1 == print time:1495975834603Thread id:Thread-2 == print time:1495975834603
- 对比Thread方法和Runnable方法的使输出结果不难发现:
. 二者均可实现多线程并发效果
. Runnable的方法可以使用一个Runnable对象创建多个线程,这多个线程共享其依赖的Runnable对象的资源,适用于多个线程处理相同资源的场景(网上举得较多的例子:卖票);Thread的方法则是完全相互独立的线程
事实上,嫌贵而言,当前Runnable使用的要比Thread方法普遍的多,除了上面说的资源共享的原因之外,Java的单继承特性也增大了Thread方法的局限性。
3. 实现Callable接口
相对于上述继承Thread类的方法和实现Runnable接口的方法,实现Callable接口的方法不但可以可以实现多线程并发,还能够处理线程的返回值或者获取执行异常。使用Callable实现多线程编程需要实现Callable的call方法(在call方法中指定返回值,抛出异常),构造与之关联的FutureTask对象,启动线程后,线程执行的结果会存储在FutureTask对象中,可以使用FutureTask的get方法获取。示例代码:
import java.util.concurrent.Callable;import java.util.concurrent.FutureTask;import static java.lang.Thread.sleep;public class MyCallable implements Callable<Integer> { private int flag = 0; public Integer call() throws Exception { System.out.println("Thread id:" + Thread.currentThread().getName() + " == print time:"+System.currentTimeMillis()); sleep(10000); System.out.println("Thread id:" + Thread.currentThread().getName() + " == print time:"+System.currentTimeMillis()); ++flag; return flag; } public static void main(String[] args) throws Exception{ MyCallable myCallable = new MyCallable(); FutureTask<Integer> future = new FutureTask<Integer>(myCallable); FutureTask<Integer> future2 = new FutureTask<Integer>(myCallable); new Thread(future).start(); new Thread(future2).start(); int Result,Result2;// while (!future.isDone()); Result = future.get();//// while(!future2.isDone()); Result2 = future2.get(); System.out.println("GET THREAD NAME:"+ Result ); System.out.println("GET THREAD NAME 2:"+Result2); }}
执行结果:
Thread id:Thread-0 == print time:1495997744617Thread id:Thread-1 == print time:1495997744617Thread id:Thread-0 == print time:1495997754625Thread id:Thread-1 == print time:1495997754625GET THREAD NAME:1GET THREAD NAME 2:2
上述代码执行逻辑与前面Runnale的示例代码类似,通过构造Thread对象来启动多线程。区别在于此处构造了futureTask方法用来用来存储线程返回值。需要注意的是,线程的Callable泛型接口里的类型和call()方法的返回值类型和FutureTask的泛型接口类型要一致。
4. 使用线程池和Executor框架
前面的三种方案,我们创建了Runnable或者Callable或者Thread的任务,扔到Thread中去启动,我们需要手动去管理各种多线程的参数,比如线程数量,线程复用,线程安全的控制等。Java5以后的版本提供了Executor技术,能够提供搭建好的线程池,为多线程提供了完整的解决方案,能够有效的管理线程数量,线程复用策略,保证线程安全,避免this逃逸问题等。
Executor提供的线程池方案包括newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool和SingleThreadExecutor(Fork/Join框架还提供了一个newWorkStealingPool),这些线程池分别提供了不同的线程管理方案,执行返回一个ExecutorService对象,这个对象可以调用execute()方法或者submit()方法,将前面定义的Runnable任务或者Callable任务或者Thread任务提交到各个线程去执行
我们以比较常用的newCachedThreadPool()为例,下面示例代码使用ExecutorService执行一个Callable对象任务,获取每个线程的返回值。
import java.util.ArrayList;import java.util.List;import java.util.concurrent.*;import static java.lang.Thread.sleep;public class MyCallable2 implements Callable<String> { public String call() throws Exception{ sleep(1000); System.out.println("terminate the thread : "+Thread.currentThread().getName()); return Thread.currentThread().getName(); } public static void main(String[] args){ ExecutorService es = Executors.newCachedThreadPool(); List<Future<String>> futureList = new ArrayList<Future<String>>(); for(int i=0;i<5;i++){ Future future = es.submit(new MyCallable2()); futureList.add(future); } for (Future f: futureList ) { while(!f.isDone()); try { System.out.println("EXECUTE RESULT:"+f.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } finally { es.shutdown(); } } }}
执行结果如下:
terminate the thread : pool-1-thread-5terminate the thread : pool-1-thread-4terminate the thread : pool-1-thread-3terminate the thread : pool-1-thread-2terminate the thread : pool-1-thread-1EXECUTE RESULT:pool-1-thread-1EXECUTE RESULT:pool-1-thread-2EXECUTE RESULT:pool-1-thread-3EXECUTE RESULT:pool-1-thread-4EXECUTE RESULT:pool-1-thread-5
使用Executors创建Runnable线程与创建Callable线程的方法类似,且不用管理返回值,相对更加简单,此处不再赘述。
- java入门学习:多线程创建-Thread,Runnable,callable和threadpool
- Java多线程Thread,Runnable, Callable<>和线程池(一)
- Java多线程Thread,Runnable, Callable<>和线程池(二)
- java多线程—Runnable、Thread、Callable
- java多线程—Runnable、Thread、Callable区别
- java 线程 --- Thread,Runnable,Callable 基础学习
- Thread、Runnable和Callable
- Thread、Runnable和Callable
- Callable ,Runnable 和 Thread
- Java 多线程(二)——创建线程(Thread、Runnable、Callable)
- java 多线程(一)---创建线程的三种方式Thread,Runnable,Callable与Future
- Java 多线程(二)——创建线程(Thread、Runnable、Callable)
- 多线程-Callable和Runnable
- java多线程 Thread 和Runnable
- java多线程 Thread 和Runnable
- java多线程Thread和Runnable
- Java多线程--Runnable和Thread
- Java -- Thread 和 Runnable 多线程
- Nio学习之通过通道实现最简单的文件复制代码
- LeetCode | 34. Search for a Range
- opencv3_java 图形图像的翻转Flip flip
- Openwrt 實戰
- 1019: 公园门票
- java入门学习:多线程创建-Thread,Runnable,callable和threadpool
- 使用jQuery 快速高效制作 网页特效
- React native 分辨率适配
- Queuing(矩阵快速幂(递推and模板))
- Android如何判断网络状态是否良好
- opencv3_java 图形图像的高斯模糊GaussianBlur GaussianBlur
- Spring Boot 使用 FreeMarker 渲染页面
- 1020: 两整数排序
- TCP建立可靠性连接的介绍