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

简介:

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


相关概念

  • 线程、进程  

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

    进程是操作系统分配资源的基础单位,而线程是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


相关文章
|
10月前
|
Java API 调度
从阻塞到畅通:Java虚拟线程开启并发新纪元
从阻塞到畅通:Java虚拟线程开启并发新纪元
483 83
|
10月前
|
存储 Java 调度
Java虚拟线程:轻量级并发的革命性突破
Java虚拟线程:轻量级并发的革命性突破
505 83
|
12月前
|
机器学习/深度学习 消息中间件 存储
【高薪程序员必看】万字长文拆解Java并发编程!(9-2):并发工具-线程池
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中的强力并发工具-线程池,废话不多说让我们直接开始。
416 0
|
12月前
|
设计模式 运维 监控
并发设计模式实战系列(4):线程池
需要建立持续的性能剖析(Profiling)和调优机制。通过以上十二个维度的系统化扩展,构建了一个从。设置合理队列容量/拒绝策略。动态扩容/优化任务处理速度。检查线程栈定位热点代码。调整最大用户进程数限制。CPU占用率100%
631 0
|
7月前
|
设计模式 缓存 安全
【JUC】(6)带你了解共享模型之 享元和不可变 模型并初步带你了解并发工具 线程池Pool,文章内还有饥饿问题、设计模式之工作线程的解决于实现
JUC专栏第六篇,本文带你了解两个共享模型:享元和不可变 模型,并初步带你了解并发工具 线程池Pool,文章中还有解决饥饿问题、设计模式之工作线程的实现
445 2
|
12月前
|
存储 缓存 安全
JUC并发—11.线程池源码分析
本文主要介绍了线程池的优势和JUC提供的线程池、ThreadPoolExecutor和Excutors创建的线程池、如何设计一个线程池、ThreadPoolExecutor线程池的执行流程、ThreadPoolExecutor的源码分析、如何合理设置线程池参数 + 定制线程池。
JUC并发—11.线程池源码分析
|
消息中间件 监控 Java
线程池关闭时未完成的任务如何保证数据的一致性?
保证线程池关闭时未完成任务的数据一致性需要综合运用多种方法和机制。通过备份与恢复、事务管理、任务状态记录与恢复、数据同步与协调、错误处理与补偿、监控与预警等手段的结合,以及结合具体业务场景进行分析和制定策略,能够最大程度地确保数据的一致性,保障系统的稳定运行和业务的顺利开展。同时,不断地优化和改进这些方法和机制,也是提高系统性能和可靠性的重要途径。
394 62
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
512 17
|
数据采集 Java 数据处理
Python实用技巧:轻松驾驭多线程与多进程,加速任务执行
在Python编程中,多线程和多进程是提升程序效率的关键工具。多线程适用于I/O密集型任务,如文件读写、网络请求;多进程则适合CPU密集型任务,如科学计算、图像处理。本文详细介绍这两种并发编程方式的基本用法及应用场景,并通过实例代码展示如何使用threading、multiprocessing模块及线程池、进程池来优化程序性能。结合实际案例,帮助读者掌握并发编程技巧,提高程序执行速度和资源利用率。
723 0

热门文章

最新文章