多线程学习
来源:互联网 发布:pokemon go挂机软件 编辑:程序博客网 时间:2024/06/16 12:48
一、概念
Java给多线程编程提供了内置的支持。一个多线程程序包含两个或多个能并发运行的部分。程序的每一部分都称作一个线程,并且每个线程定义了一个独立的执行路径。
多线程是多任务的一种特别的形式。多线程比多任务需要更小的开销。
这里定义和线程相关的另一个术语:进程:一个进程包括由操作系统分配的内存空间,包含一个或多个线程。一个线程不能独立的存在,它必须是进程的一部分。一个进程一直运行,直到所有的非守候线程都结束运行后才能结束。
多线程能满足程序员编写非常有效率的程序来达到充分利用CPU的目的,因为CPU的空闲时间能够保持在最低限度。
有效利用多线程的关键是理解程序是并发执行而不是串行执行的。例如:程序中有两个子系统需要并发执行,这时候就需要利用多线程编程。
通过对多线程的使用,可以编写出非常高效的程序。不过请注意,如果你创建太多的线程,程序执行的效率实际上是降低了,而不是提升了。
请记住,上下文的切换开销也很重要,如果你创建了太多的线程,CPU花费在上下文的切换的时间将多于执行程序的时间!
线程的生命周期
线程经过其生命周期的各个阶段。下图显示了一个线程完整的生命周期。
- 新建状态: 一个新产生的线程从新状态开始了它的生命周期。它保持这个状态直到程序start这个线程。
- 运行状态: 当一个新状态的线程被start以后,线程就变成可运行状态,一个线程在此状态下被认为是开始执行其任务
- 就绪状态: 当一个线程等待另外一个线程执行一个任务的时候,该线程就进入就绪状态。当另一个线程给就绪状态的线程发送信号时,该线程才重新切换到运行状态。
- 休眠状态: 由于一个线程的时间片用完了,该线程从运行状态进入休眠状态。当时间间隔到期或者等待的时间发生了,该状态的线程切换到运行状态。
- 终止状态: 一个运行状态的线程完成任务或者其他终止条件发生,该线程就切换到终止状态。
线程的优先级
每一个Java线程都有一个优先级,这样有助于操作系统确定线程的调度顺序。Java优先级在MIN_PRIORITY(1)和MAX_PRIORITY(10)之间的范围内。默认情况下,每一个线程都会分配一个优先级NORM_PRIORITY(5)。
具有较高优先级的线程对程序更重要,并且应该在低优先级的线程之前分配处理器时间。然而,线程优先级不能保证线程执行的顺序,而且非常依赖于平台。
二、创建一个线程
Java提供了两种创建线程方法:
- 通过实现Runnable接口。
- 通过继承Thread类本身。
通过实现Runnable接口来创建线程
创建一个线程,最简单的方法是创建一个实现Runnable接口的类。
为了实现Runnable,一个类只需要执行一个方法调用run(),声明如下:
public void run()
你可以重写该方法,重要的是理解的run()可以调用其他方法,使用其他类,并声明变量,就像主线程一样。
在创建一个实现Runnable接口的类之后,你可以在类中实例化一个线程对象。
Thread定义了几个构造方法,下面的这个是我们经常使用的:
Thread(Runnable threadOb,String threadName);
这里,threadOb 是一个实现Runnable 接口的类的实例,并且 threadName指定新线程的名字。
新线程创建之后,你调用它的start()方法它才会运行。
void start();
demo
public class TestThread { @Test public void testThread(){ for (int i = 0; i < 10; i++) { Thread thread = new Thread(new createRunnableThread(i), String.valueOf(i)); thread.start(); } }// java7写法// private Runnable createRunnableThread(int i) {// return new Runnable() {// @Override// public void run() {// System.out.println(i);// }// };// }// java8写法 private Runnable createRunnableThread(int i) { return () -> System.out.println(i); }}
通过继承Thread来创建线程
创建一个线程的第二种方法是创建一个新的类,该类继承Thread类,然后创建一个该类的实例。
继承类必须重写run()方法,该方法是新线程的入口点。它也必须调用start()方法才能执行。
demo
public class TestThread { @Test public void testThread() throws InterruptedException { for (int i = 0; i < 10; i++) { Thread thread = new Thread(new createThread(i), String.valueOf(i)); thread.start(); } }}class createThread extends Thread { private int i = 0; createThread(int i) { this.i = i; } public void run() { System.out.println(i); }}
三、Thread 方法
上述方法是被Thread对象调用的。下面的方法是Thread类的静态方法。
四、工具类
public class ThreadPool extends ThreadGroup { /** * 线程池是否关闭 */ private boolean isClosed = false; /** * 工作队列 */ private LinkedList<Runnable> workQueue; /** * 线程池的id */ private static int threadPoolID = 1; public ThreadPool(int poolSize) { //poolSize 表示线程池中的工作线程的数量 //指定ThreadGroup的名称 super(String.valueOf(threadPoolID)); //继承到的方法,设置是否守护线程池 setDaemon(true); //创建工作队列 workQueue = new LinkedList<>(); for (int i = 0; i < poolSize; i++) { //创建并启动工作线程,线程池数量是多少就创建多少个工作线程 new WorkThread(i).start(); } } /** * 向工作队列中加入一个新任务,由工作线程去执行该任务 */ public synchronized void execute(Runnable task) { if (isClosed) { throw new IllegalStateException(); } if (task != null) { //向队列中加入一个任务 workQueue.add(task); //唤醒一个正在getTask()方法中待任务的工作线程 notify(); } } /** * 从工作队列中取出一个任务,工作线程会调用此方法 */ private synchronized Runnable getTask(int threadid) throws InterruptedException { while (workQueue.size() == 0) { if (isClosed) { return null; } //System.out.println("工作线程"+threadid+"等待任务..."); //如果工作队列中没有任务,就等待任务 wait(); } //System.out.println("工作线程"+threadid+"开始执行任务..."); //反回队列中第一个元素,并从队列中删除 return (Runnable) workQueue.removeFirst(); } /** * 关闭线程池 */ public synchronized void closePool() { if (!isClosed) { //等待工作线程执行完毕 waitFinish(); isClosed = true; //清空工作队列 workQueue.clear(); //中断线程池中的所有的工作线程,此方法继承自ThreadGroup类 interrupt(); } } /** * 等待工作线程把所有任务执行完毕 */ private void waitFinish() { synchronized (this) { isClosed = true; //唤醒所有还在getTask()方法中等待任务的工作线程 notifyAll(); } //activeCount() 返回该线程组中活动线程的估计值。 Thread[] threads = new Thread[activeCount()]; //enumerate()方法继承自ThreadGroup类,根据活动线程的估计值获得线程组中当前所有活动的工作线程 int count = enumerate(threads); //等待所有工作线程结束 for (int i = 0; i < count; i++) { try { //等待工作线程结束 threads[i].join(); } catch (InterruptedException ex) { ex.printStackTrace(); } } } /** * 内部类,工作线程,负责从工作队列中取出任务,并执行 */ private class WorkThread extends Thread { private int id; private WorkThread(int id) { //父类构造方法,将线程加入到当前ThreadPool线程组中 super(ThreadPool.this, id + ""); this.id = id; } @Override public void run() { //isInterrupted()方法继承自Thread类,判断线程是否被中断 while (!isInterrupted()) { Runnable task = null; try { //取出任务 task = getTask(id); } catch (InterruptedException ex) { ex.printStackTrace(); } //如果getTask()返回null或者线程执行getTask()时被中断,则结束此线程 if (task == null) { return; } try { //运行任务 task.run(); } catch (Throwable t) { t.printStackTrace(); } } } }}
测试
public static void main(String[] args) throws InterruptedException { ThreadPool threadPool = new ThreadPool(3); //创建一个有个3工作线程的线程池 Thread.sleep(500); //休眠500毫秒,以便让线程池中的工作线程全部运行 //运行任务 long start = System.currentTimeMillis();//开始时间 for (int i = 0; i <= 500; i++) { //创建500个任务 threadPool.execute(createTask(i)); } threadPool.waitFinish(); //等待所有任务执行完毕 long end = System.currentTimeMillis(); System.out.println("总用时 ============:" + (end - start) + "ms"); threadPool.closePool(); //关闭线程池}private static Runnable createTask(final int taskID) { return new Runnable() { @Override public void run() { System.out.println("Hello world----" + Thread.currentThread() + "------" + taskID); } };}
- 学习多线程
- 多线程学习
- 多线程学习
- 多线程学习
- 多线程学习
- 多线程学习
- 多线程学习
- 学习多线程
- 多线程学习
- 多线程学习
- 多线程学习
- 多线程学习
- 多线程学习
- 多线程学习
- 多线程学习
- 多线程学习
- 多线程学习
- 多线程学习
- pandas:填充缺失值 fillna("missing") 和fillna("missing",inplace=True)的区别
- Effective Java之用私有构造器或者枚举类型强化Singleton属性(三)
- [iOS11 + Xcode9 各大好文汇总]
- C#项目的IIS环境搭建
- Deep Reinforcement learning
- 多线程学习
- LeetCode(5) Longest Palindromic Substring解题报告
- 存储与服务器的连接方式对比(DAS,NAS,SAN)
- SJTUOJ1003路径法解决问题
- 数据挖掘十大经典算法——CART
- 初探React-native (二)
- 点击率预估
- Xcode插件,自动生成Getter,带你飞
- 利用ES6-Promise()方法封装原始jsonp实现跨域请求公用方法(告别使用JQuery封装好的jsonp)