您的位置:首页 > 编程语言

并发编程

2016-03-17 16:14 246 查看
基本线程机制

并发编程将程序划分为多个分离的、独立运行的任务。通过多线程机制,这些独立的任务中的每一个都将由执行线程来驱动。(就是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;
}
}


结果截图:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: