并发编程
2016-03-17 16:14
246 查看
基本线程机制
并发编程将程序划分为多个分离的、独立运行的任务。通过多线程机制,这些独立的任务中的每一个都将由执行线程来驱动。(就是Runnable的实现类与Thread的关系)一个线程就是在进程中的一个单一的顺序控制流。单个进程可以拥有多个并发执行的任务。
在使用线程的时候,CPU将轮流给每个任务分配其占用时间,每个任务都觉得自己一直在占用CPU,但事实上,CPU的时间被划分为一个个小片段分配给所有任务。简单的讲,就是CPU在这个很短的时间段内执行这个线程,在那个短时间段内执行哪一个线程,从微观上不同时,宏观上是同时执行多个任务。
Runnable和Thread
线程(Thread)可以驱动任务(Runnable实现类),这时就需要一种描述任务的方式,即实现Runnable接口,实现其run()方法。
通常,任务中的run()方法被写成无限循环的形式。除非某个条件使得run()终止,否则将永远运行下去。该线程任务未执行结束,代表线程不能死亡,垃圾回收器就无法清除它。(Thread区别于其他对象,当普通的对象失去引用的时候,垃圾回收器将会回收内存)
示例代码
注:开辟线程的能力不仅仅main()线程拥有,其他子线程也可以开辟其他线程。
Executor的使用
java.util.concurrent包中的Executor可以用于管理Thread对象。
注意,ExecutorService对象是使用静态的Executor方法创建的。
①CachedThreadPool将为每个任务创建线程。
示例代码
②FixedThreadPool,有限线程集,在创建线程池的时候指定线程数量,即限制在线程池中同时运行的线程数。若指定为1的话,同时又有99个任务,最后会造成99个任务按顺序执行,即执行完一个,下一个才开始执行。
③SingleThreadExecutor,即线程数量限制为1的FixedThreadPool,通常放入的是长期存活的任务。如果向SingleThreadExecutor提交多个任务,就像上面说的,这些任务将会排队。所有任务使用的是相同的线程。(代码与上面类似,不再重复贴出)
摘自书本,假设有大量的线程,它们运行的任务将使用文件系统,你可以用SingleThreadExecutor来运行这些线程,以确保任意时刻在任何线程中都只有唯一任务在运行,所以在这种方式中,你不需要在共享资源上处理同步。
上面三个线程池使用的Runnable实现类
从任务中产生返回值
Runnable是执行工作的任务,但它没有返回值。若希望任务完成时返回一个值,则需要实现Callable接口,而不是Runnable接口。指定实现Callable接口的范型(以确定call的返回值),并重写call方法。最后必须使用ExecutorService.submit()方法调用它。
submit()方法会产生Future对象,可以调用isDone()来查询Future是否完成,调用get()方法,获取执行结果。如果没有用isDone()检查就直接调用get()方法,将产生阻塞,直至结果被计算出来。
示例代码:
结果截图:
并发编程将程序划分为多个分离的、独立运行的任务。通过多线程机制,这些独立的任务中的每一个都将由执行线程来驱动。(就是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对象。
注意,ExecutorService对象是使用静态的Executor方法创建的。
①CachedThreadPool将为每个任务创建线程。
示例代码
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来运行这些线程,以确保任意时刻在任何线程中都只有唯一任务在运行,所以在这种方式中,你不需要在共享资源上处理同步。
上面三个线程池使用的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; } }
结果截图:
相关文章推荐
- MyEclipse 每次保存都要building workspace的解决方法
- 【转】Java并发编程:深入剖析ThreadLocal
- 数据流形式参数 访问counter
- 几款python集成开发环境
- ubuntu 使用Eclipse对FFmpeg进行调试
- C#隐式/显示实现接口方法详解
- Python进程
- 监听ContentProvider数据改变
- C++编程小记(一)
- maven web 项目中启动报错java.lang.ClassNotFoundException: org.springframework.web.util.Log4jConfigListener
- Flask download file vs django download file
- PHP网页乱码处理
- python 编码问题
- C++ 之 auto_ptr and shared_ptr
- java中的SuppressWarnings注解的用法
- 请用普通的互斥锁编程实现一个读写锁
- 对Python面向对象的理解
- Python (九) 协程以及数据库操作
- java IO流读写文件
- php正则字符串查找替换