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

简介:

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


相关概念

  • 线程、进程  

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

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

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

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

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

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

    线程空间的一个实时状态

  • 线程状态

    创建、运行、阻塞、销毁

    102506481.png

  • 线程与锁

    加锁是为了同步调度
    锁的类型:共享锁、互斥锁;只读锁、可写锁
    死锁
    争夺资源
    调度失当


线程并发模型

  • 阻塞队列

    当队列不满足操作条件时,操作线程将进入阻塞状态
    get()时,如果队列为空,则阻塞线程,直到成功执行了add()
    add()时,如果队列已满,则阻塞线程,直到成功执行了get()
    最常用的一种并发调度器

    eg :生产者-消费者

  • 闭锁

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

    eg:登机

  • 关卡

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

    eg:大巴车

线程实现

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

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 =  new Thread(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的返回结果
项目应用
实际上是一个“大巴车”模型


测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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 ( int i =  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);
assert task !=  null ;
int result = task.get();
System.out.println(result);
taskIndex++;
}
catch (InterruptedException e) {
e.printStackTrace();
catch (ExecutionException e) {
e.printStackTrace();
}
}
}

task类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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 {
int result =  0 ;
for ( int i=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


相关文章
|
2月前
|
并行计算 Java 数据处理
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
SpringBoot高级并发实践:自定义线程池与@Async异步调用深度解析
235 0
|
1月前
|
存储 Java 数据库
如何处理线程池关闭时未完成的任务?
总之,处理线程池关闭时未完成的任务需要综合考虑多种因素,并根据实际情况选择合适的处理方式。通过合理的处理,可以最大程度地减少任务丢失和数据不一致等问题,确保系统的稳定运行和业务的顺利开展。
119 64
|
1月前
|
消息中间件 监控 Java
线程池关闭时未完成的任务如何保证数据的一致性?
保证线程池关闭时未完成任务的数据一致性需要综合运用多种方法和机制。通过备份与恢复、事务管理、任务状态记录与恢复、数据同步与协调、错误处理与补偿、监控与预警等手段的结合,以及结合具体业务场景进行分析和制定策略,能够最大程度地确保数据的一致性,保障系统的稳定运行和业务的顺利开展。同时,不断地优化和改进这些方法和机制,也是提高系统性能和可靠性的重要途径。
119 62
|
1月前
|
安全
List并发线程安全问题
【10月更文挑战第21天】`List` 并发线程安全问题是多线程编程中一个非常重要的问题,需要我们认真对待和处理。只有通过不断地学习和实践,我们才能更好地掌握多线程编程的技巧和方法,提高程序的性能和稳定性。
198 59
|
26天前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
53 12
|
1月前
|
安全 Java
线程安全的艺术:确保并发程序的正确性
在多线程环境中,确保线程安全是编程中的一个核心挑战。线程安全问题可能导致数据不一致、程序崩溃甚至安全漏洞。本文将分享如何确保线程安全,探讨不同的技术策略和最佳实践。
41 6
|
1月前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
58 6
|
1月前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
1月前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####
|
2月前
|
Java
【编程进阶知识】揭秘Java多线程:并发与顺序编程的奥秘
本文介绍了Java多线程编程的基础,通过对比顺序执行和并发执行的方式,展示了如何使用`run`方法和`start`方法来控制线程的执行模式。文章通过具体示例详细解析了两者的异同及应用场景,帮助读者更好地理解和运用多线程技术。
36 1