36)线程状态:
- NEW 刚创建 (new)
- RUNNABLE 就绪 (start)
- RUNNING 运行中 (run)
- BLOCK 阻塞 (sleep)
- TERMINATED 结束

线程被动地暂停和停止:不能及时释放资源。
线程主动暂停和停止:
- 定期检测共享变量
- 如果需要暂停和停止,先释放变量,再主动动作
- 暂停:Thread.sleep(),休眠
- 终止:run方法结束,线程终止
在线程中监控volatile变量,在发现变量改变时可以做出对应的变化,释放相应的资源。
37)普通线程:run方法运行结束时结束。
守护线程:run方法运行结束或main函数结束时结束。{.setDaemon(true);}
38)并行编程的困难:任务分配和执行过程的高度耦合。
并行模式:
- 主从模式(Master-slave)
- Worker模式(Worker-Worker)
Java并发编程:
- Thread/Runnable/Thread组管理
- Executor
- Fork-Join框架
线程组Thread Group
- 线程的集合
- 树形结构,大线程组可以包括小线程组
- 可以通过enumerate方法遍历组内的线程,执行操作
- 能够有效管理多个线程,但是管理效率低
- 任务分配和执行过程高度耦合
- 重复创建线程、关闭线程操作,无法重用线程
Executor
- 分离任务的创建和执行者的创建
- 线程重复利用(new线程的代价过大)
共享线程池的理念
- 预设好的多个Thread,可弹性增加
- 多次执行很多很小的任务
- 任务创建和执行过程解耦
- 程序员无需关心线程池执行任务过程
Executor的主要类:ExecutorService、ThreadPoolExecutor、Future
- Executor.newCachedThreadPool/newFixedThreadPool创建线程池、
- ExecutorService线程池服务
- Callable具体的逻辑对象(线程类){Callable和Runnable是等价的,而且Callable的call方法可以有返回值}
- Future返回结果
public class Server { //线程池 private ThreadPoolExecutor executor; public Server(){ executor=(ThreadPoolExecutor)Executors.newCachedThreadPool(); //executor=(ThreadPoolExecutor)Executors.newFixedThreadPool(5); } //向线程池提交任务 public void submitTask(Task task){ System.out.printf("Server: A new task has arrived\n"); executor.execute(task); //执行 无返回值 System.out.printf("Server: Pool Size: %d\n",executor.getPoolSize()); System.out.printf("Server: Active Count: %d\n",executor.getActiveCount()); System.out.printf("Server: Completed Tasks: %d\n",executor.getCompletedTaskCount()); } public void endServer() { executor.shutdown(); } }
public class Main { public static void main(String[] args) throws InterruptedException { // 创建一个执行服务器 Server server=new Server(); // 创建100个任务,并发给执行器,等待完成 for (int i=0; i<100; i++){ Task task=new Task("Task "+i); Thread.sleep(10); server.submitTask(task);//不关心线程池如何去完成100个任务 } server.endServer(); } }
import java.util.Date; import java.util.concurrent.TimeUnit; /** * Task 任务类 * @author Tom * */ public class Task implements Runnable { private String name; public Task(String name){ this.name=name; } public void run() { try { Long duration=(long)(Math.random()*1000); System.out.printf("%s: Task %s: Doing a task during %d seconds\n",Thread.currentThread().getName(),name,duration); Thread.sleep(duration); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("%s: Task %s: Finished on: %s\n",Thread.currentThread().getName(),name,new Date()); } }
Fork-Join(分治编程)
适用于整体计算量不太确定的编程。(最小任务量可确定)(类似归并排序思想)
Fork-Join的关键类
- ForkJoinPool任务池
- RecursiveAction(用于没有返回结果的任务)
- RecursiveTask(用于有返回值的任务)
import java.math.BigInteger; import java.util.concurrent.RecursiveTask; //分任务求和 public class SumTask extends RecursiveTask<Long> { private int start; private int end; public SumTask(int start, int end) { this.start = start; this.end = end; } public static final int threadhold = 5; @Override protected Long compute() { Long sum = 0L; // 如果任务足够小, 就直接执行 boolean canCompute = (end - start) <= threadhold; if (canCompute) { for (int i = start; i <= end; i++) { sum = sum + i; } } else { // 任务大于阈值, 分裂为2个任务 int middle = (start + end) / 2; SumTask subTask1 = new SumTask(start, middle); SumTask subTask2 = new SumTask(middle + 1, end); invokeAll(subTask1, subTask2); Long sum1 = subTask1.join(); //用join阻塞,等待返回结果 Long sum2 = subTask2.join(); // 结果合并 sum = sum1 + sum2; } return sum; } }
import java.util.concurrent.ExecutionException; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; //分任务求和 public class SumTest { public static void main(String[] args) throws ExecutionException, InterruptedException { //创建执行线程池 ForkJoinPool pool = new ForkJoinPool(); //ForkJoinPool pool = new ForkJoinPool(4); //创建任务 SumTask task = new SumTask(1, 10000000); //提交任务 ForkJoinTask<Long> result = pool.submit(task); //等待结果 do { System.out.printf("Main: Thread Count: %d\n",pool.getActiveThreadCount()); System.out.printf("Main: Paralelism: %d\n",pool.getParallelism()); try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } while (!task.isDone()); //输出结果 System.out.println(result.get().toString()); } }