【技术交流】让我们来谈一谈多线程和并发任务

相信你已经了解过多线程的概念,不妨咱们来回顾下,做个暖场如何

相关概念

线程、进程  

依赖包含关系、相似(状态)、区别(内存共享、资源共享、成本)

进程是操作系统分配资源的基础单位,而线程是CPU执行的基础单位。

线程与线程间是并列且独立的。

线程空间、ThreadLocal、线程上下文

线程运行时所占用的内存、锁、cpu等资源的一个虚拟视图

线程的一个局部变量,可以理解为与当前线程绑定的一个map

线程空间的一个实时状态

线程状态

创建、运行、阻塞、销毁

线程状态图

线程与锁

加锁是为了同步调度

锁的类型:共享锁、互斥锁;只读锁、可写锁

死锁

争夺资源

调度失当

线程并发模型

阻塞队列

当队列不满足操作条件时,操作线程将进入阻塞状态

  • get()时,如果队列为空,则阻塞线程,直到成功执行了add()
  • add()时,如果队列已满,则阻塞线程,直到成功执行了get()

最常用的一种并发调度器

eg :生产者-消费者。库房满时,生产者阻塞,直到消费者取走了库存;库房空时,消费者阻塞,直到生产者增加了库存。

闭锁

闭锁线程转换到“开门”状态之前,任何尝试“进门”的线程都会被阻塞

eg:登机。在允许登机之前,所有乘客都要等待。

关卡

所有线程都执行到“关卡”点之前,任何尝试“过关”的线程都会被阻塞

eg:大巴车。在所有人都到齐之前,大巴车不会开动。已上车的人都要等待。

线程实现

java多线程实现,有两种方法。继承Thread,实现接口Runable。大多数时候我们采用后者。原因很简单:单继承,多实现,况且java的设计原则有一条是“面向接口编程”。

测试类

public class TestMain {
    @Test
    public void testThread(){
        //
        Thread th1 = new TestNoSynThread();
        Thread th2 = new TestNoSynThread();
        th1.start();
        th2.start();
    }
    @Test
    public void testRunable(){
        //
        TestNoSynRunable r = new TestNoSynRunable();
        Thread th1 = new Thread(r,"thread-a");
        Thread th2 = newT hread(r,"thread-b");
        th1.start();
        th2.start();
    }
}

注:start方法只是启动线程,使线程处于可运行状态,并没有运行。一旦得到cpu,就开始执行重写的run方法。run执行完毕,线程结束。

下面再来介绍并发实现的另一种方式,实际上是Runable方式上的封装。在JDK1.5出现之后,Sun发布的多线程并发处理的工具包

java.util.concurrent

  • Executor 并发任务执行器的顶级抽象,只针对Runnable

  • ExecutorService 对Executor进行扩展,支持Callable和Future

  • Callable 对Runnable进行扩展,提供了返回值。

  • Future 阻塞线程,直到Callable返回了值

  • FutureTask 实现了Callable和Future 可以简单理解为同时是生产者和消费者的类

  • 其它 闭锁、关卡等实现

并发任务使用

  • 声明一个ExecutorService
  • 向ExecutorService 提交一个或多个Callable,并获取Future
  • 从Future中获取Callable的返回结果

项目应用

实际上是一个“大巴车”模型

测试类

public class TestExecutorService {
    private int SIZE = 10;
    /**
    * 计算1+2+...+100.
    *
    * @author wuyichen-ghq
    * @since 2013-12-31
    */
    @Test
    public void main() {
        ExecutorService exeService = Executors.newCachedThreadPool();
        // 任务列表,分成1+10、11+20、。。。、91+100
        List<FutureTask<Integer>> taskList = new ArrayList<FutureTask<Integer>>(SIZE);
        for(inti = 0; i < SIZE; i++) {
            TestFutureTask task = new TestFutureTask(i * 10+ 1, (i + 1) * 10);
            taskList.add(new FutureTask<Integer>(task));
        }
        // 逐个提交任务(这里可以将任务创建和提交放在一个for里)
        for(FutureTask<Integer> task : taskList) {
            exeService.submit(task);
        }
        // 逐个获取任务结果
        FutureTask<Integer> task = null;
        // 任务序列号
        int taskIndex = 0;
        try{
            while(taskIndex < taskList.size()) {
            task = taskList.get(taskIndex);
            asserttask != null;
            intresult = task.get();
            System.out.println(result);
            taskIndex++;
            }
        } catch(InterruptedException e) {
            e.printStackTrace();
        } catch(ExecutionException e) {
            e.printStackTrace();
        }
    }
}

task类

public class TestFutureTask implements Callable<Integer>{
    private int begin;
    private int end;
    /**
    * TODO:(构造方法描述)
    *
    * @author wuyichen-ghq
    * @since 2013-12-31
    * @param i
    */
    public TestFutureTask(int begin,int end) {
        this.begin = begin;
        this.end = end;
    }
    /**
    * TODO:(方法描述)
    *
    * @author wuyichen-ghq
    * @since 2013-12-31
    * @throws 无
    * @see java.util.concurrent.Callable#call()
    *
    */
    @Override
    public Integer call() throws Exception {
        intresult = 0;
        for(inti=begin;i<=end;i++){
            result = i + result;
        }
        return result;
    }
   }

要注意的地方:

  • 异常处理
  • ExecutorService有两个方法:submit、execute

that's all!如果文章中什么错误,请与我联系,也欢迎您跟我邮件交流哦!

邮箱:wyc_job@163.com

本文出自 “ ATIP團戰術策劃部” 博客,请务必保留此出处 http://atip3.blog.51cto.com/6312771/1347150