并发编程
来源:互联网 发布:linux安装apache 编辑:程序博客网 时间:2024/05/16 23:41
基本线程机制
并发编程将程序划分为多个分离的、独立运行的任务。通过多线程机制,这些独立的任务中的每一个都将由执行线程来驱动。(就是Runnable的实现类与Thread的关系)一个线程就是在进程中的一个单一的顺序控制流。单个进程可以拥有多个并发执行的任务。
在使用线程的时候,CPU将轮流给每个任务分配其占用时间,每个任务都觉得自己一直在占用CPU,但事实上,CPU的时间被划分为一个个小片段分配给所有任务。简单的讲,就是CPU在这个很短的时间段内执行这个线程,在那个短时间段内执行哪一个线程,从微观上不同时,宏观上是同时执行多个任务。
Runnable和Thread
线程(Thread)可以驱动任务(Runnable实现类),这时就需要一种描述任务的方式,即实现Runnable接口,实现其run()方法。
通常,任务中的run()方法被写成无限循环的形式。除非某个条件使得run()终止,否则将永远运行下去。该线程任务未执行结束,代表线程不能死亡,垃圾回收器就无法清除它。(Thread区别于其他对象,当普通的对象失去引用的时候,垃圾回收器将会回收内存)
示例代码
public class ThreadAndRunnable implements Runnable { private int countDown = 10; private static int taskCount = 0; // 任务数 private final int id = taskCount++; // id用于区分多个任务实例 public String toString() { return "id " + "(" + id + ") a " + (countDown > 0 ? countDown : "归零"); } public void run() { while(countDown-- > 0) { System.out.println(this.toString()); Thread.yield(); } } public static void main(String[] args) { Thread mThread = new Thread(new ThreadAndRunnable()); mThread.start(); }}
注:开辟线程的能力不仅仅main()线程拥有,其他子线程也可以开辟其他线程。
Executor的使用
java.util.concurrent包中的Executor可以用于管理Thread对象。
public ThreadPoolExecutor(int corePoolSize, // 核心线程数 int maximunPoolSize, // 线程池容纳最大线程数 long keepAliveTime, // 非核心线程闲置的超时时长 TimeUnit unit, // 时间单位 BlockingQueue<Runnable> workQueue, //线程池的任务队列, execute提交的runnable对象 ThreadFactory threadFactory // 为线程池提供创建线程的功能)
注意,ExecutorService对象是使用静态的Executor方法创建的。
①CachedThreadPool将为每个任务创建线程 。 它是一种线程数量不定的线程池, 他只有非核心线程, 并且最大数目为 Integer.MAX_VALUE。当线程池的所有线程都处于活动状态时, 线程池会创建新的线程来处理新的任务, 否则利用空闲线程来处理新任务。 而空闲线程超时60后, 将会回收。 也就是说,当整个线程池都置于空闲状态后, 线程池的线程都会超时而被停止, 这个时候 CachedThreadExecutor 几乎不占用任何系统资源。
适合执行大量耗时较少的任务
示例代码
import java.util.concurrent.*;public class CachedThreadPool { public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); // 创建管理Thread的Executor for(int i = 0; i < 3; i++) { exec.execute(new MyRunnable()); // 创建3个任务,扔进线程池 } // 调用shutdown()将不能再往里面添加任务,否则抛RejectedExecutionException异常 exec.shutdown(); }}
②FixedThreadPool,有限线程集,在创建线程池的时候指定线程数量,即限制在线程池中同时运行的线程数。若指定为1的话,同时又有99个任务,最后会造成99个任务按顺序执行,即执行完一个,下一个才开始执行。
线程固定的线程池,线程处于空闲状态时,并不会回收,除非线程池被关闭。 由于核心线程都不会被回收, 所以能更加快速响应外界请求。
public class FixedThreadPool { public static void main(String[] args) { ExecutorService exec = Executors.newFixedThreadPool(3); // 指定线程数量 for(int i = 0; i < 99; i++) { exec.execute(new MyRunnable()); } exec.shutdown(); }}
③SingleThreadExecutor,即线程数量限制为1的FixedThreadPool,通常放入的是长期存活的任务。如果向SingleThreadExecutor提交多个任务,就像上面说的,这些任务将会排队。所有任务使用的是相同的线程。(代码与上面类似,不再重复贴出)
摘自书本,假设有大量的线程,它们运行的任务将使用文件系统,你可以用SingleThreadExecutor来运行这些线程,以确保任意时刻在任何线程中都只有唯一任务在运行,所以在这种方式中,你不需要在共享资源上处理同步。
④ ScheduleThreadPool
通过 newScheduledThreadPool 创建, 核心线程数量固定, 而非核心线程是没有限制的, 并且闲置时会被回收。 这类线程池主要用于执行定时任务和具有固定周期的重复任务
上面三个线程池使用的Runnable实现类
class MyRunnable implements Runnable { private int countDown = 5; private static int taskCount = 0; private int id = taskCount++; public String toString() { return "Runnable id: " + "(" + id + ")" + " countDown:" + (countDown > 0 ? countDown : "归零"); } public void run() { while(countDown-- > 0) { System.out.println(this.toString()); } Thread.yield(); // 让步其他线程执行 }}
从任务中产生返回值
Runnable是执行工作的任务,但它没有返回值。若希望任务完成时返回一个值,则需要实现Callable接口,而不是Runnable接口。指定实现Callable接口的范型(以确定call的返回值),并重写call方法。最后必须使用ExecutorService.submit()方法调用它。
submit()方法会产生Future对象,可以调用isDone()来查询Future是否完成,调用get()方法,获取执行结果。如果没有用isDone()检查就直接调用get()方法,将产生阻塞,直至结果被计算出来。
示例代码:
import java.util.concurrent.*;import java.util.*;public class CallableDemo { public static void main(String[] args) { ExecutorService exec = Executors.newCachedThreadPool(); // 存放Future对象 ArrayList<Future<String>> futureList = new ArrayList<Future<String>>(); for(int i = 0; i < 10; i++) { futureList.add(exec.submit(new MyCallable(i))); } for(Future<String> future: futureList) { try { System.out.println(future.get()); } catch (InterruptedException e) { System.out.println(e); } catch (ExecutionException e) { System.out.println(e); } finally { exec.shutdown(); } } }}class MyCallable implements Callable<String> { private int id; public MyCallable (int id) { this.id = id; } public String call() { return "result of MyCallable " + id; }}
结果截图:
- 并发编程--并发集合
- 并发编程
- 并发编程
- 并发编程
- 并发编程
- 并发编程
- 并发编程
- 并发编程
- 并发编程
- 并发编程
- 并发编程
- 并发编程
- 并发编程
- 并发编程
- 并发编程
- 并发编程
- 并发编程
- 并发编程
- java操作mysql实例 让代码跑起来
- 在PL/SQL中怎样判断查询的结果是否为空
- CMD命令重新注册 asp.net 4.0
- Android开发实例详解之IMF(Android SDK Sample—SoftKeyboard)
- 如何确定一个数为素数
- 并发编程
- java.lang.UnsatisfiedLinkError: Couldn't load libjniFramework from loader
- 解决Genymotion出现Unable to load VirtualBox engine问题
- wine地址
- 让Android Studio的智能感知不区分大小写
- Apache Spark Jobs 性能调优(一)
- fread的误区(以文本格式打开文件)
- 麻省理工-线性代数-乘法和逆矩阵
- 白话空间统计二十:相似性搜索(四)