java多线程的使用与原理

    xiaoxiao2021-03-25  175

    1、线程池简介:     多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。         假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间。     如果:T1 + T3 远大于 T2,则可以采用线程池,以提高服务器性能。                 一个线程池包括以下四个基本组成部分:                 1、线程池管理器(ThreadPool):用于创建并管理线程池,包括 创建线程池,销毁线程池,添加新任务;                 2、工作线程(PoolWorker):线程池中线程,在没有任务时处于等待状态,可以循环的执行任务;                 3、任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等;                 4、任务队列(taskQueue):用于存放没有处理的任务。提供一种缓冲机制。                      线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。     线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目,看一个例子:     假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程完成。在线程池中,线程数一般是固定的,所以产生线程总数不会超过线程池中线程的数目,而如果服务器不利用线程池来处理这些请求则线程总数为50000。一般线程池大小是远小于50000。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高效率。

        代码实现中并没有实现任务接口,而是把Runnable对象加入到线程池管理器(ThreadPool),然后剩下的事情就由线程池管理器(ThreadPool)来完成了

     

    [java]  view plain  copy package mine.util.thread;      import java.util.LinkedList;   import java.util.List;      /**   * 线程池类,线程管理器:创建线程,执行任务,销毁线程,获取线程基本信息   */   public final class ThreadPool {       // 线程池中默认线程的个数为5       private static int worker_num = 5;       // 工作线程       private WorkThread[] workThrads;       // 未处理的任务       private static volatile int finished_task = 0;       // 任务队列,作为一个缓冲,List线程不安全       private List<Runnable> taskQueue = new LinkedList<Runnable>();       private static ThreadPool threadPool;          // 创建具有默认线程个数的线程池       private ThreadPool() {           this(5);       }          // 创建线程池,worker_num为线程池中工作线程的个数       private ThreadPool(int worker_num) {           ThreadPool.worker_num = worker_num;           workThrads = new WorkThread[worker_num];           for (int i = 0; i < worker_num; i++) {               workThrads[i] = new WorkThread();               workThrads[i].start();// 开启线程池中的线程           }       }          // 单态模式,获得一个默认线程个数的线程池       public static ThreadPool getThreadPool() {           return getThreadPool(ThreadPool.worker_num);       }          // 单态模式,获得一个指定线程个数的线程池,worker_num(>0)为线程池中工作线程的个数       // worker_num<=0创建默认的工作线程个数       public static ThreadPool getThreadPool(int worker_num1) {           if (worker_num1 <= 0)               worker_num1 = ThreadPool.worker_num;           if (threadPool == null)               threadPool = new ThreadPool(worker_num1);           return threadPool;       }          // 执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定       public void execute(Runnable task) {           synchronized (taskQueue) {               taskQueue.add(task);               taskQueue.notify();           }       }          // 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定       public void execute(Runnable[] task) {           synchronized (taskQueue) {               for (Runnable t : task)                   taskQueue.add(t);               taskQueue.notify();           }       }          // 批量执行任务,其实只是把任务加入任务队列,什么时候执行有线程池管理器觉定       public void execute(List<Runnable> task) {           synchronized (taskQueue) {               for (Runnable t : task)                   taskQueue.add(t);               taskQueue.notify();           }       }          // 销毁线程池,该方法保证在所有任务都完成的情况下才销毁所有线程,否则等待任务完成才销毁       public void destroy() {           while (!taskQueue.isEmpty()) {// 如果还有任务没执行完成,就先睡会吧               try {                   Thread.sleep(10);               } catch (InterruptedException e) {                   e.printStackTrace();               }           }           // 工作线程停止工作,且置为null           for (int i = 0; i < worker_num; i++) {               workThrads[i].stopWorker();               workThrads[i] = null;           }           threadPool=null;           taskQueue.clear();// 清空任务队列       }          // 返回工作线程的个数       public int getWorkThreadNumber() {           return worker_num;       }          // 返回已完成任务的个数,这里的已完成是只出了任务队列的任务个数,可能该任务并没有实际执行完成       public int getFinishedTasknumber() {           return finished_task;       }          // 返回任务队列的长度,即还没处理的任务个数       public int getWaitTasknumber() {           return taskQueue.size();       }          // 覆盖toString方法,返回线程池信息:工作线程个数和已完成任务个数       @Override       public String toString() {           return "WorkThread number:" + worker_num + "  finished task number:"                   + finished_task + "  wait task number:" + getWaitTasknumber();       }          /**       * 内部类,工作线程       */       private class WorkThread extends Thread {           // 该工作线程是否有效,用于结束该工作线程           private boolean isRunning = true;              /*           * 关键所在啊,如果任务队列不空,则取出任务执行,若任务队列空,则等待           */           @Override           public void run() {               Runnable r = null;               while (isRunning) {// 注意,若线程无效则自然结束run方法,该线程就没用了                   synchronized (taskQueue) {                       while (isRunning && taskQueue.isEmpty()) {// 队列为空                           try {                               taskQueue.wait(20);                           } catch (InterruptedException e) {                               e.printStackTrace();                           }                       }                       if (!taskQueue.isEmpty())                           r = taskQueue.remove(0);// 取出任务                   }                   if (r != null) {                       r.run();// 执行任务                   }                   finished_task++;                   r = null;               }           }              // 停止工作,让该线程自然执行完run方法,自然结束           public void stopWorker() {               isRunning = false;           }       }   }  

     

    测试代码:

    [java]  view plain  copy package mine.util.thread;      //测试线程池   public class TestThreadPool {       public static void main(String[] args) {           // 创建3个线程的线程池           ThreadPool t = ThreadPool.getThreadPool(3);           t.execute(new Runnable[] { new Task(), new Task(), new Task() });           t.execute(new Runnable[] { new Task(), new Task(), new Task() });           System.out.println(t);           t.destroy();// 所有线程都执行完成才destory           System.out.println(t);       }          // 任务类       static class Task implements Runnable {           private static volatile int i = 1;              @Override           public void run() {// 执行任务               System.out.println("任务 " + (i++) + " 完成");           }       }   }  

     

    运行结果:

    WorkThread number:3  finished task number:0  wait task number:6 任务 1 完成 任务 2 完成 任务 3 完成 任务 4 完成 任务 5 完成 任务 6 完成 WorkThread number:3  finished task number:6  wait task number:0

    分析:由于并没有任务接口,传入的可以是自定义的任何任务,所以线程池并不能准确的判断该任务是否真正的已经完成(真正完成该任务是这个任务的run方法执行完毕),只能知道该任务已经出了任务队列,正在执行或者已经完成。

    2、Java类库中提供的线程池简介:

         java提供的线程池更加强大,相信理解线程池的工作原理,看类库中的线程池就不会感到陌生了。

    Java通过Executors提供四种线程池,分别为: newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。 newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。 newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

     

    (1) newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。示例代码如下:

    Java代码   package test;   import java.util.concurrent.ExecutorService;   import java.util.concurrent.Executors;   public class ThreadPoolExecutorTest {    public static void main(String[] args) {     ExecutorService cachedThreadPool = Executors.newCachedThreadPool();     for (int i = 0; i < 10; i++) {      final int index = i;      try {       Thread.sleep(index * 1000);      } catch (InterruptedException e) {       e.printStackTrace();      }      cachedThreadPool.execute(new Runnable() {       public void run() {        System.out.println(index);       }      });     }    }   }  

     

    线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。   (2) newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。示例代码如下:

    Java代码   package test;   import java.util.concurrent.ExecutorService;   import java.util.concurrent.Executors;   public class ThreadPoolExecutorTest {    public static void main(String[] args) {     ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);     for (int i = 0; i < 10; i++) {      final int index = i;      fixedThreadPool.execute(new Runnable() {       public void run() {        try {         System.out.println(index);         Thread.sleep(2000);        } catch (InterruptedException e) {         e.printStackTrace();        }       }      });     }    }   }  

      因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。 定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()

     

    (3)  newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:

    Java代码   package test;   import java.util.concurrent.Executors;   import java.util.concurrent.ScheduledExecutorService;   import java.util.concurrent.TimeUnit;   public class ThreadPoolExecutorTest {    public static void main(String[] args) {     ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);     scheduledThreadPool.schedule(new Runnable() {      public void run() {       System.out.println("delay 3 seconds");      }     }, 3, TimeUnit.SECONDS);    }   }  

      表示延迟3秒执行。

    定期执行示例代码如下:

    Java代码   package test;   import java.util.concurrent.Executors;   import java.util.concurrent.ScheduledExecutorService;   import java.util.concurrent.TimeUnit;   public class ThreadPoolExecutorTest {    public static void main(String[] args) {     ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);     scheduledThreadPool.scheduleAtFixedRate(new Runnable() {      public void run() {       System.out.println("delay 1 seconds, and excute every 3 seconds");      }     }, 13, TimeUnit.SECONDS);    }   }  

      表示延迟1秒后每3秒执行一次。

     

    (4) newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下:

    Java代码   package test;   import java.util.concurrent.ExecutorService;   import java.util.concurrent.Executors;   public class ThreadPoolExecutorTest {    public static void main(String[] args) {     ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();     for (int i = 0; i < 10; i++) {      final int index = i;      singleThreadExecutor.execute(new Runnable() {       public void run() {        try {         System.out.println(index);         Thread.sleep(2000);        } catch (InterruptedException e) {         e.printStackTrace();        }       }      });     }    }   }  

      结果依次输出,相当于顺序执行各个任务。

    你可以使用JDK自带的监控工具来监控我们创建的线程数量,运行一个不终止的线程,创建指定量的线程,来观察: 工具目录:C:\Program Files\Java\jdk1.6.0_06\bin\jconsole.exe 运行程序做稍微修改:

    Java代码   package test;   import java.util.concurrent.ExecutorService;   import java.util.concurrent.Executors;   public class ThreadPoolExecutorTest {    public static void main(String[] args) {     ExecutorService singleThreadExecutor = Executors.newCachedThreadPool();     for (int i = 0; i < 100; i++) {      final int index = i;      singleThreadExecutor.execute(new Runnable() {       public void run() {        try {         while(true) {          System.out.println(index);          Thread.sleep(10 * 1000);         }        } catch (InterruptedException e) {         e.printStackTrace();        }       }      });      try {       Thread.sleep(500);      } catch (InterruptedException e) {       e.printStackTrace();      }     }    }   }  

    转载请注明原文地址: https://ju.6miu.com/read-1081.html

    最新回复(0)