`
Everyday都不同
  • 浏览: 724946 次
  • 性别: Icon_minigender_1
  • 来自: 宇宙
社区版块
存档分类
最新评论

多线程 & 异步调用 的理解

阅读更多

最近做项目,高并发的情况比较常见,因此常常需要用到多线程。而之前一直对多线程处于一个比较模糊的状态,这次终于清晰了点儿。其实理解多线程可以和异步调用结合起来理解会比较好。

 

对于同步调用和异步调用,可以用以下伪代码来粗略的看一下:

 

同步调用:

public void test() {
   //某段代码
		
   //这里是入db的操作
   this.saveDataToDb(Map params);
}

 异步调用:

public void test() {
   //某段代码
		
   //这里是入db的操作
  new Thread(new SaveDataToDb(Map param)).start();
}

 其中SaveDataToDb类是一个实现了Runnable接口的线程。

 

在同步调用中,你必须等待“某段代码”执行完毕后,再执行saveDataToDb操作。而入db是一个相对耗时的操作。在非并发的情形下,这样做性能上的劣势还可能不能体现出来。但当是高并发的情况和不定时被执行的情况下呢?我们总不能执行到saveDataToDb处时,就一直等待saveDataToDb执行完,才开始接收下一次的任务请求吧!所以就必须开启另一个线程。

 

于是就用到了异步调用。把saveDataToDb的逻辑放到一个线程类的run方法里,而当执行到入db的操作处时,我们就启用该线程来“异步”地执行入db的操作。这样,在高并发的情况下,“下一次”的请求就可以不用等到“这一次”入db的操作执行完毕后再执行了。

 

具体到实际情景就是:如果执行某项任务需要甲乙协作完成,甲做完“下一步”给乙做,而乙做的东西又比较耗时,则此次任务必须是甲等待乙完成之后再接收下一次该任务。其中的等待时间就浪费了。如果是异步的话,则甲完成他的部分,可以不必等待乙完成再接收下一次任务。甲每次完成就把他的结果部分丢给乙,而乙是可以不必跟甲在同一流程里执行的。这样就达到了“错开”的效果。也节省了时间。

 

当然,我们更为合理的做法是用一个线程池去控制多线程,线程池可以负责多个线程的创建、等待、调度和销毁等。因为如果在高并发的情况下,你每到入db处,就new一个线程,当new的线程越来越多时,会造成内存的大量占用。

 

拿甲乙的例子来说,线程池就是负责创建了很多个“乙”,他们共同协作完成比较耗时的入db的操作。效率上因此更加高效了。线程池此时可以理解成“包工头”,当一个“乙”做完之后,就可以接着做了,而当一个“乙”正在做,则不会把任务分配给他,只有当他做完之后,才会再次分配入db的任务给他。

 

我们不妨在web项目初始化的时候,就创建一个线程池的类,这个线程池类定义好了一些多线程的配置然后定义一个调度线程的静态方法。我们需要用线程池调用线程时,就调用该静态方法即可。

 

需要注意的是,“异步”调用受线程影响很大。就拿上述的入db操作的线程来说,可能在高并发的情形下,线程未能及时被线程池回收而不够用,入db的操作就会被down掉或不能及时入db。所以需要我们好好控制线程池的配置。

 

【2016-1-18相关补充】

观察下面的代码:

public static void main(String[] args) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("模拟订阅");
			}
		}).start();
		
		new Thread(new Runnable() {
			@Override
			public void run() {
				while(true) {
					try {
						Thread.sleep(3000);
						System.out.println("每隔3s do something。。。========");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}).start();
		
//		new Thread(new Runnable() {
//			@Override
//			public void run() {
				while(true) {
					try {
						Thread.sleep(6000);
						System.out.println("每隔6s do otherthing。。。");
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
//			}
//		}).start();
	}

 运行该main程序之后,你会发现,虽然第二步用的是一个while循环,但是它是写在一个内部的匿名线程类里面,你会发现还是会重复  打印 [每隔3s do something。。。========]2次之后再打印一次 [每隔6s do otherthing。。。]的情况;程序并没有在第二步被while循环阻塞。

但是如果你第二步不是写在匿名线程里,则编译都会报错,因为第三步根本就变成unreachable的。

注意,上述代码的写法中,第三步的whille循环可用线程套起来也可以不用,但注意一定要sleep , 否则程序会永远阻塞在第三步。第二步就不会每隔一段时间去执行啦。(其实第二步如果你不sleep第三步也是执行不到的,所以无论哪个while都应该sleep)

上面的写法其实之前我也不是很熟悉,但今天碰到了顺便学习了一下。这是非常实用的。比如一个程序启动往往有每隔段时间去检查队列的需求,这时候其实你并不需要劳师动众去专门写一个定时任务(因为此时逻辑很简单哒)。巧妙应用while是完全能达到效果滴。

综上所述,线程其实也是异步的一个很重要的反映。

1
4
分享到:
评论
7 楼 haoran_10 2015-09-21  
楼主,异步调用,直接用消息中间件,千万别用多线程处理,性能很差的,用多线程反而会拖累服务器的性能。
6 楼 Everyday都不同 2015-09-18  
18735384527 写道
虽然是多线程,但是cup时刻都只能运行1个线程,如果入库的操作没有线程睡眠之类的操作,那让它入库之后,再重新跑,性能也没什么提升吧

cpu是通过时间分片来实现多线程效果的
5 楼 18735384527 2015-09-17  
虽然是多线程,但是cup时刻都只能运行1个线程,如果入库的操作没有线程睡眠之类的操作,那让它入库之后,再重新跑,性能也没什么提升吧
4 楼 Everyday都不同 2015-09-17  
diarbao 写道
明白你说的意思。
可是现在有一个问题
你怎么能确定你的保存是否成功了呢?
一般情况下我感觉系统都是需要同步进行的呢。
比如你保存是否成功都需要一个返回值 然后来告诉用户 你的操作是否成功了吧?
这个问题是怎么解决的呢。谢谢

您好 ,我这边考虑的是在高并发的情形下,并不是普通的增删改查的“增”。我关心的是在高并发条件下,每次都得入库时,此时不能采取同步的方式。因为高并发,每次都得入库。所以才必须使用异步的策略。而并不关心响应信息。一般这样就会有我说的入db并不及时或出现根本没入库的情况。
3 楼 Everyday都不同 2015-09-17  
cywhoyi 写道
一般不是这么搞,宁愿加lock,也不会采取new thread,哪怕你池子中获取都行,也不要new Thread。
1.耗资源,不管开辟thread,还是回收thread
2.假设很多请求,每次都是new,太可怕不可想象

是的,一般不会去new Thread, 而是用线程池去调用多线程
2 楼 cywhoyi 2015-09-17  
一般不是这么搞,宁愿加lock,也不会采取new thread,哪怕你池子中获取都行,也不要new Thread。
1.耗资源,不管开辟thread,还是回收thread
2.假设很多请求,每次都是new,太可怕不可想象
1 楼 diarbao 2015-09-17  
明白你说的意思。
可是现在有一个问题
你怎么能确定你的保存是否成功了呢?
一般情况下我感觉系统都是需要同步进行的呢。
比如你保存是否成功都需要一个返回值 然后来告诉用户 你的操作是否成功了吧?
这个问题是怎么解决的呢。谢谢

相关推荐

    Java多线程实现异步调用实例

    在本实例中,我们将深入探讨如何使用Java实现多线程以实现异步调用,并理解其背后的机制。 首先,多线程允许一个程序同时执行多个任务。在Java中,我们可以通过继承`Thread`类或实现`Runnable`接口来创建线程。在这...

    Labview2015多线程异步调用工程

    在“Labview2015多线程异步调用工程”中,我们探讨的核心是利用多线程和异步调用来提高程序执行效率和并发能力。这个工程的目的是让主线程能持续快速地进行轮询,同时多个子线程可以并行处理耗时的任务,从而优化...

    多线程异步调用(并参递参数)

    本文将深入探讨“多线程异步调用(并参递参数)”这一主题,通过经典代码示例来解释其原理和应用。 首先,我们要理解多线程的概念。在单线程环境中,程序执行是顺序的,一次只能做一件事。而在多线程环境中,程序...

    Labview异步调用示例

    异步调用在LabVIEW中通常涉及事件结构、多线程和回调函数等概念。首先,事件结构是LabVIEW中处理异步操作的核心工具。当特定事件发生时,如用户交互、定时器触发或特定的VI完成执行,事件结构会分发相应的代码分支...

    如何用Java回调和线程实现异步调用.pdf

    "如何用Java回调和线程实现异步调用" 在软件开发中,异步调用是一种非阻塞式调用方式,用于在处理比较耗时的任务时保证程序的连续性和实时性。实现异步调用的关键在于解决三个技术难题:程序阻塞问题、异步消息的...

    LabVIEW中异步调用+可重入VI设置

    这在多线程或多任务环境中尤其有用。在LabVIEW中,可重入VI通过避免共享数据和使用局部变量来实现线程安全性。为了设置一个VI为可重入,你需要右键点击VI的图标,选择“VI属性”,然后在“常规”选项卡中勾选“可重...

    线程与异步调用

    这不仅有助于编写出更加高效和响应性更好的程序,还能在多线程和并发编程时,更好地理解和处理同步问题、死锁以及竞态条件等复杂问题。在阅读和学习这类知识时,通常需要结合实际编程实践,通过编写代码来加深对这些...

    C# 多线程异步执行

    在多线程异步场景中,我们可以定义一个事件,当某个异步操作完成时触发这个事件,通知调用者任务已完成。 结合这些概念,我们可以构建一个模拟多线程下载图片的程序。以下是一个基本步骤: 1. **创建事件**:定义...

    C#多线程与异步的区别

    本文将深入探讨C#中的多线程与异步操作,旨在帮助开发者更好地理解这两种并发机制的区别及其应用场景。 #### 多线程和异步操作的异同 多线程和异步操作都是提高程序性能的有效手段,它们都能避免主调用线程被阻塞...

    异步调用流程图

    异步调用流程图是理解这一概念的重要工具。下面,我们将深入探讨异步调用的概念、原理及其在实际应用中的表现。 首先,异步调用的基本思想是,当一个函数或方法被调用时,它并不立即返回结果,而是立即返回一个代表...

    C#多线程与异步的区别详解

    多线程和异步操作两者都可以达到避免调用线程阻塞的目的,从而提高软件的可响应性。甚至有些时候我们就认为多线程和异步操作是等同的概念。但是,多线程和异步操作还是有一些区别的。而这些区别造成了使用多线程和...

    AsyncCalls(异步调用函数)

    1. **异步方法调用**:异步调用函数允许你将一个方法的调用包装成一个异步任务,然后在后台线程执行。这样,主线程可以继续处理其他任务,而不会被长时间运行的操作阻塞。 2. **事件处理**:在异步操作完成后,通常...

    安卓异步加载网络资源(多线程&AsynvTask)

    本项目是根据慕课网《android必学-异步加载》视频教学所开发的一套异步加载网络资源的...其中分别用到了多线程、AsyncTask实现异步加载的功能。 里面还包括了: json解析、网络请求、LruCache缓存、滚动优化等实用技能。

    Unity异步线程调用主线程脚本

    Unity异步线程调用主线程脚本程序,在Unity中异步线程调用主线程会报错,所以编写了一个Loom

    wcf多线程和异步操作

    它提供了丰富的功能,包括支持多线程和异步操作,这在处理大量并发请求或长时间运行的操作时尤为重要。本篇文章将深入探讨WCF中的多线程和异步操作,以及通过一个读取文件的示例来展示其应用。 ### 异步服务调用 ...

    异步多线程Demo

    异步多线程结合了两者的优点,通过异步调用实现线程间的非阻塞通信,提升系统效率。 4. **线程的创建**:在Java中,可以通过`Thread`类的子类化或实现`Runnable`接口来创建线程;在Python中,可以使用`threading`...

    C#多线程异步源码示例

    本文将深入探讨C#多线程异步源码及其实现算法,帮助开发者更好地理解和运用这些技术。 一、多线程 1. **什么是多线程**:多线程是指一个进程中同时运行多个不同的执行流,每个执行流(线程)都可以独立地执行任务...

    Java多线程实现异步调用的方法

    Java多线程实现异步调用是提高程序效率的关键技术之一。在Java中,通过创建新线程并让它们独立运行来实现异步调用,这样可以使得主线程不被长时间阻塞,从而提高程序的响应速度。以下将详细介绍如何在Java中实现这一...

    C# MVC TASK异步调用测试!

    假设了一个场景,用户在局域网Web服务器上下了一个单,程序将这个订单发送到远程服务器,然后用户付款到远程服务器, ...有可能用户下单之后就把本网站的下单页面给关闭...关键字:C# ,Asp.Net, MVC, TASK异步调用测试!

    vc 多线程实例同步,异步

    总的来说,理解和掌握VC++中的多线程同步和异步是提升程序性能和稳定性的重要手段。开发者需要深入理解各种线程同步机制,合理运用异步操作,确保代码的正确性和可维护性。在实际项目中,应根据需求选择合适的线程...

Global site tag (gtag.js) - Google Analytics