为什么需要线程池 在生产环境中,我们不能无限制的创建线程,主要原因如下: 线程创建与销毁的代价并不低; 如果可运行的线程数量多于可用处理器的数量,有些线程将会闲置,大量闲置的线程会消耗系统资源(内存)并给垃圾收集器带来压力; 大量线程竞争CPU也会造成不小的性能开销。 Executor框架 Executor框架在Java 5中被引入,其内部使用了线程池机制。它在java.util.cocurrent包下,通过该框架来控制线程的启动、执行和关闭,可以简化并发编程的操作。 Executor框架包括:线程池,Executor,Executors,ExecutorService等(Callable与Future本篇不进行讨论)。 Executor接口 我们先来了解一下其中的Executor接口: public interface Executor { void execute(Runnable command); } Executor接口的定义非常简单,但它却为灵活 继续阅读 >>


董恒毅 18/09/13 21:38:05
synchronized 同步方法 方法内的变量线程安全,实例变量非线程安全。调用关键字synchronized声明的方法一定是排队运行的,如果不是共享资源,那么根本就没有同步的需要。 关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法(函数)当做锁。对于多线程访问同一对象,哪个对象先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁Lock,其他线程就只能等待;但是如果多个线程访问多个对象,则JVM会创建多个锁。 A线程先持有object对象的Lock锁,B线程可以以异步的方式调用object对象中的非synchronized类型的方法;但B线程如果在这时调用object对象中的synchronized类型的方法需要等待,也就是同步。 脏读是指在读取实例变量时,此值已经被其他线程更改过了。对于实例变量的getValue和setValue方法都要是同步的才能保证不出现脏读。 关键字synchronized拥有锁重入的功能,也就是在使用synchr 继续阅读 >>


李猛 18/08/06 19:22:51
注:本文中的部分内容摘抄自他人博客,如有侵权,请联系我,侵删~ 本篇博客主要讲述 synchronized 关键字的实现原理以及 JDK 1.6 后对 synchronized 的种种优化。synchronized 的使用不再赘述。 博主目前依旧存在的疑惑 请在阅读完此篇博客之后,帮助博主回答这三个问题: 多线程争夺 Monitor 的具体过程是怎样的?是根据 ObjectMonitor 中的 _count 值判断当前 Monitor 是否被锁定吗? JVM 如果检测到在单线程环境下执行同步代码(StringBuffer),是会进行锁消除呢,还是会使用偏向锁? 对于偏向锁的撤销过程及膨胀过程,博主只是在一些博客的基础上给出了自己的理解!不权威,建议阅读源码,博主对这部分知识的讲解持怀疑态度,如果在阅读的过程中发现博主对偏向锁的撤销与膨胀理解有误,请指出,感激不尽~(网上基本上没有从源码角度分析的,对于偏向锁撤销与升级的详细过程也是众说纷纭) 引言 我们先来看一份代码: 继续阅读 >>


董恒毅 18/04/27 11:38:27
并发模式是指I/O处理单元和多个逻辑单元之间协调完成任务的方法 1、半同步/半异步模式 1.1半同步/半异步模式 【1】同步:程序完全按照代码顺序执行;异步:程序的执行需要由系统事件来驱动。常见的系统事件包括中断,信号等。 【2】同步线程:按照同步方式运行的线程;异步线程:按照异步方式运行的线程。 异步线程执行效率高,实时性强,但是程序相对负责,难以调试和扩展,不适合于大量的并发。 同步线程效率相对较低,实时性较差,但逻辑简单。 像服务器这种既要求较好的实时性,又要能同时处理多个客户请求的应用程序,就要同时使用同步线程和异步线程来实现,即半同步/半异步模式。 【3】半同步/半异步模式中,同步线程用于处理客户逻辑,即逻辑单元;异步线程用于处理I/O事件,即I/O处理单元。 异步线程监听到客户请求之后,就将其封装成请求对象插入请求队列,请求队列通知某个工作在同步模式的工作线程来读取并处理该请求对象。具体选择哪个工作线程取决于请求队列的设计 【4】半同步/半 继续阅读 >>


闫钰晨 17/07/29 15:58:01
前言之前的前言 本文作于6月中旬,当时对于很多概念不是很理解,所以写到一半实在进行不下去,通过最近的学习终于理解了一些,赶紧总结记下。 前言 本篇主要总结服务器端开发中的一些基本的框架。 如果你在东区二楼点过黄焖鸡,相信你一定能更好的理解。 正文 I/O模型 主要可以分为同步I/O,异步I/O 两大类。 同步I/O 我们可以理解为,在I/O事件发生后(出现了I/O请求),由应用程序负责处理I/O,或者说,内核向应用程序通知I/O就绪事件。 理论上来说,阻塞I/O(如read一直等待),I/O复用(如select,epoll),信号I/O都是同步I/O。 异步I/O 这俩当然是相反的咯,在I/O事件发生后(出现了I/O请求),由内核负责处理I/O,内核向应用程序通知I/O完成事件,比如Linux下的aio,(还有C++的asio??) 理解 之前对于同步和异步总是很混乱,看过之后才明白,同步I/O是由应用程序来处理,而异步只是应用程序将要做的I/O处理提前告诉了内核,一旦需要处理,内核直接按照之前的要求 继续阅读 >>


康艺杰 17/07/25 09:34:13
Concurrency and competition   并发与竞态 竞态 竞态条件(race c […] 继续阅读 >>


张明瑞 17/04/30 05:07:43
C++11一个重要的特性就是对多线程的支持。 何谓并发 计算机领域的并发指的是在单个系统里同时执行多个独立的任务,而非顺序的进行一些活动。 并发的两种方式: 1.多核处理器,每个任务在自己核心上执行,称为硬件并发,机器能够真正的并行多个任务; 2.单核机器,通过多任务操作系统的切换功能,同时运行多个程序。机器只能在某一时刻执行一个任务,不过它每秒可以执行多次任务切换。因为任务切换的很快,以至于无法感觉任务在何时被暂时挂起,而切换到另一任务,如今仍然称这样的系统为并发, 关系:当应用在多任务切换的环境下和真正并发的环境下执行相比,行为还是有区别的。任务切换在多核处理器上仍然适用。 并发的途径 1.多进程并发——有多个 单线程的 进程 2.多线程并发——单个进程运行多个进程 为什么使用并发 1.为了分离关注点 把不同的关注点分离开来,是处理复杂性的一个原则。通过将相关的代码与无关的代码分离,可使程序更容易理解和测试;同时可使每个线程的逻辑变的更加简单。 2.为了性能 两种方式利用并发提升性能: 继续阅读 >>


杜肖孟 17/03/27 22:35:15
一、背景 我们实际系统中有很多操作,是不管做多少次,都应该产生一样的效果或返回一样的结果。 例如: 前端重复提交选中的数据,应该后台只产生对应这个数据的一个反应结果。 我们发起一笔付款请求,应该只扣用户账户一次钱,当遇到网络重发或系统bug重发,也应该只扣一次钱; 发送消息,也应该只发一次,同样的短信发给用户,用户会哭的; 创建业务订单,一次业务请求只能创建一个,创建多个就会出大问题。 等等很多重要的情况,这些逻辑都需要幂等的特性来支持。 二、幂等性概念 幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。 在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“getUsername()和setTrue()”函数就是一个幂等函数. 更复杂的操作幂等保 继续阅读 >>


王伟豪 16/08/17 20:27:41
原文链接 简单使用Lock锁     Java 5中引入了新的锁机制——java.util.concurrent.locks中的显式的互斥锁:Lock接口,它提供了比synchronized更加广泛的锁定操作。Lock接口有3个实现它的类:ReentrantLock、ReetrantReadWriteLock.ReadLock和ReetrantReadWriteLock.WriteLock,即重入锁、读锁和写锁。lock必须被显式地创建、锁定和释放,为了可以使用更多的功能,一般用ReentrantLock为其实例化。为了保证锁最终一定会被释放(可能会有异常发生),要把互斥区放在try语句块内,并在finally语句块中释放锁,尤其当有return语句时,return语句必须放在try字句中,以确保unlock()不会过早发生,从而将数据暴露给第二个任务。因此,采用lock加锁和释放锁的一般形式如下: [java] view plain  继续阅读 >>


王伟豪 16/07/25 15:10:43
1.客户端: 客户端程序使用poll同事监听用户输入和网络连接,并利用splice函数将用户输入内容直接定向到网络连接上以发送之,从而实现数据零拷贝,提高了程序执行效率。 splice函数简介: #include <fcntl.h> ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags); splice用于在两个文件描述符之间移动数据, 也是零拷贝。 ①fd_in参数是待输入描述符。如果它是一个管道文件描述符,则②off_in必须设置为NULL;否则off_in表示从输入数据流的何处开始读取,此时若为NULL,则从输入数据流的当前偏移位置读入。 ③/④fd_out/off_out与上述相同,不过是用于输出。 ⑤len参数指定移动数据的长度。 ⑥flags参数则控制数据如何移动: SPLICE_F_NONBLOCK:splice 操作不会被阻塞。然而,如果文件描述符没 继续阅读 >>


杜仑 16/07/19 22:08:34