学习资料来自http://ifeve.com/java-concurrency-thread-directory/

一、多线程

  1. 进程和线程的区别: 一个程序运行至少一个进程,一个进程至少包含一个线程。
  2. 多线程: 多线程使得在一个程序内部能够拥有多个线程并行执行,一个线程的执行可以被认为是一个cpu在执行该程序,当一个程序运行在多线程下,就好像有多个CPU在同时执行该程序。

多线程在同一个程序内部并发执行,因此会对相同的内存空间进行并发读写操作。

思考:

  1. 如果一个线程在读一个内存时,另一个线程正向该内存进行写操作,那么进行读操作的线程将获得什么结果呢?是写操作之前的旧值?还是写操作成功之后的新值?或者一半新一半旧的值?
  2. 如果两个线程同是写一个内存,在操作完成之后又是什么结果呢?是第一个线程写入的值?还是第二个线程写入的值?还是两个线程共同写入的一个混合值?

二、多线程的优点

1、资源利用率更好

比如CPU在等待磁盘读取的时间非常空闲,可以利用这一段时间去做一些其他的事情。

2、程序设计在某些情况下更简单

比如单线程去操作两个文件的读取和处理,需要记录每个文件的读取和处理状态。相反,如果用两个线程分别处理一个文件,一个线程在读取的时候就会阻塞另一个线程,此时,被阻塞的线程就可以去执行处理的操作。不但提升磁盘和CPU利用率,编程也更加容易实现。

3、程序响应更快

例如服务器在某一个端口监听进来的请求,当一个请求到来时它去处理这个请求,处理完了再返回去监听其他请求。假设这个请求需要占用大量的时间呢?

另一种方式是服务器监听线程把进来的请求传递给工作者线程,然后马上返回去监听,这样就能够接受和处理更多客户端发送过来的请求,服务的响应也更快了。

三、多线程的代价

1、设计更复杂

一般来说,多线程应用程序比单线程应用程序更加复杂,在多线程访问共享数据的时候,线程之间的交互往往非常复杂,不正确的线程同步产生的错误非常难以被发现,并且重现以修复。

2、上下文切换的开销

当CPU执行一个线程切换到执行另外一个线程的时候,它需要先存储当前线程的本地数据、程序指针等,然后载入另一个线程的本地数据、程序指针等,最后才开始执行。这种切换叫做上下文切换(context switch),CPU会在一个上下文(context)中执行一个线程,然后切换到另一个上下文(context)执行另外一个线程。

如果没有必要应该尽量减少上下文的切换。

3、增加资源消耗

除了CPU,线程还需要一些内存来维持它本地的堆栈,也需要占用操作系统中一些资源来管理线程。我们可以写一个程序创建100个线程,然后这些线程只是等待什么都不做,然后看看占用了多少内存。

四、并发编程模型

并发编程模型指定了系统中的多线程如何通过协作来完成分配给它们的作业,不同的并发模型采用不同的方式拆分作业,同时线程间的协作和交互方式也不相同。

1、 并发模型与分布式系统之间的相似性

并发模理类似于分布式系统中使用的很多体系结构,在分布式系统中进程之间可以

通信(进程可能在不同的机器中),在并发系统中线程之间也可以相互通信。例如为工作者们(线程)分配作业的模型一般与分布式系统中的负载均衡系统比较相似。

2、 并行工作者

委托者将传入的作业被分配给不同的工作者上,每个工作者完成整个任务,工作者们运作在不同的线程上,甚至可能在不同的CPU上。

优点:容易理解,只需要添加更多的工作者来提高系统的并行度。

缺点:

  1. 并发工作者通常需要访问一些共享数据,无论是内存中还是数据库中,一旦涉及到共享状态情况就会变得复杂。线程需要以某种方式存取共享数据,以确保某个线程的修改能够对其他线程可见。线程需要避免竟态、死锁以及很多其他共享状态的并发问题。

等待访问共享数据时,线程之间的互相等待会丢失部分并行性,许多并发数据结构是阻塞的,意味着在某个时刻只有一个或者很少的线程能访问,导致共享数据出现竞争状态,出现一定串行化。

  1. 无状态的工作者: 共享状态能够被其他线程修改,所以工作者在每次需要的时候必须重读状态,以确保每次都能访问到最新的副本。工作者无法在内部保存这个状态称为无状态的。特别是状态保存在外部数据库中的时候,每次重读会导致速度变慢。
  2. 任务顺序是不确定的: 作业A可能在作业B之前就被分配工作者了,但是作业B反而有可能在作业A之前执行,也就是无法保证哪个作业最先或者最后被执行。

3、  流水线模型

也叫反应器系统、事件驱动系统或者无共享模型。

类似于工厂生产线上的工人们,每个工作者只负责作业中的部分工作,当完成了自己这部分工作就转发给下一个工作者,每个工作者在自己的线程中运行,并不会和其他工作者共享状态。

在实际中可能会有多个不同的虚拟流水线同时动作,现实可能是这样的情况。

Actors和Channels

Actors模型中每个工作者都被称为actor。Actor之间可以直接异步地发送和处理消息,actor可以用来实现一个或多个前面描述的那种作业处理流水线。

Channel模型中,工作都之间不直接进行通信。相返,它们在不同的通道中发布自己的消息(事件)。其他工作者可以在这些通道上监听消息,发送者无需知道谁在监听。

流水线模型的优点:

  1. 无需共享的状态
  2. 有状态的工作者
  3. 较好的硬件整合
  4. 合理的作业顺序

流水线模型的缺点:

  1. 作业执行往往分布到多个工作者上,并因此分布到项目中的多个类上。这样导致在追踪某个作业到底被什么代码执行时变得困难。
  2. 加大了代码编写的难度,有时工作者的代码需要写成回调处理的形式。若在代码中嵌入过多的回调处理,往往会出现所谓的回调地狱(callback hell)现像。

4、  函数式执行(Functional Parallelism)

函数式并行的基本思想是采用函数调用实现程序,函数被看作是代理人(agents)或者actor, 函数之间可以像流水线模型(AKA反应器或者事件驱动系统)那样互相发送消息。

         思考:使用哪种并发模型好呢?

通常情况下,这个答案取决于你的系统打算做什么。如果你的作业本身就是并行的、独立的并且没有必要共享状态,你可能会使用并行工作者模型去实现你的系统。

很多作业都不是自然并行和独立的,对于这种类型的系统,使用流水线并发模型能够更好的发挥它的优势,而且比并行工作者模型更有优势。

Java并发模型(一)的更多相关文章

  1. 构建自己的Java并发模型框架

    Java的多线程特性为构建高性能的应用提供了极大的方便,可是也带来了不少的麻烦.线程间同步.数据一致性等烦琐的问题须要细心的考虑,一不小心就会出现一些微妙的,难以调试的错误. 另外.应用逻辑和线程逻辑 ...

  2. 构建Java并发模型框架

    Java的多线程特性为构建高性能的应用提供了极大的方便,但是也带来了不少的麻烦.线程间同步.数据一致性等烦琐的问题需要细心的考虑,一不小心就会出现一些微妙的,难以调试的错误.另外,应用逻辑和线程逻辑纠 ...

  3. Java并发模型框架

    构建Java并发模型框架 Java的多线程特性为构建高性能的应用提供了极大的方便,但是也带来了不少的麻烦.线程间同步.数据一致性等烦琐的问题需要细心的考虑,一不小心就会出现一些微妙的,难以调试的错误. ...

  4. 一网打尽 Java 并发模型

    本篇文章我们来探讨一下并发设计模型. 可以使用不同的并发模型来实现并发系统,并发模型说的是系统中的线程如何协作完成并发任务.不同的并发模型以不同的方式拆分任务,线程可以以不同的方式进行通信和协作. 并 ...

  5. Java并发编程基础之volatile

    首先简单介绍一下volatile的应用,volatile作为Java多线程中轻量级的同步措施,保证了多线程环境中“共享变量”的可见性.这里的可见性简单而言可以理解为当一个线程修改了一个共享变量的时候, ...

  6. Java内存模型---并发编程网 - ifeve.com

    Java内存模型 转自:http://ifeve.com/java-memory-model-6/ 原文地址  作者:Jakob Jenkov 译者:张坤 Java内存模型规范了Java虚拟机与计算机 ...

  7. 《Java并发编程实战》第十六章 Java内存模型 读书笔记

    Java内存模型是保障多线程安全的根基,这里不过认识型的理解总结并未深入研究. 一.什么是内存模型,为什么须要它 Java内存模型(Java Memory Model)并发相关的安全公布,同步策略的规 ...

  8. JVM-7.Java内存模型与高效并发

    更多内容参见<并发与同步>系列 一.引子 二.JMM 三.Java中的线程 四.线程安全 五.锁优化       一.引子 运算能力 摩尔定律:晶体管数量,代表的CPU的频率 Amdahl ...

  9. Java多线程与并发模型之锁

    这是一篇总结Java多线程开发的长文.文章是从Java创建之初就存在的synchronized关键字引入,对Java多线程和并发模型进行了探讨.希望通过此篇内容的解读能帮助Java开发者更好的理清Ja ...

随机推荐

  1. css:html() text() val()

    转http://www.jb51.net/article/35867.htm .html()用为读取和修改元素的HTML标签    对应js中的innerHTML .html()是用来读取元素的HTM ...

  2. js 解析json字符串

    server端返回的数据例如以下: {"list":[{"id":1,"name":"汉族"},{"id&qu ...

  3. cenos7 修改hostname

    hostnamectl set-hostname Linuxidc 如何在CentOS 7上修改主机名 在CentOS中,有三种定义的主机名:静态的(static),瞬态的(transient),和灵 ...

  4. python3 configparser对配置文件读写

    import configparser #read data from conf filecf=configparser.ConfigParser()cf.read("biosver.cfg ...

  5. vue-bus 组件通信插件

    vue-bus 一个 Vue.js 事件中心插件,同时支持 Vue 1.0 和 2.0 原因 Vue 2.0 重新梳理了事件系统,因为基于组件树结构的事件流方式实在是让人难以理解,并且在组件结构扩展的 ...

  6. linearLayout 和 relativeLayout的属性区别

    LinearLayout和RelativeLayout 共有属性: java代码中通过btn1关联次控件 android:id="@+id/btn1" 控件宽度 android:l ...

  7. 如何编译文件(gcc + nasm)

    [0]README 编译文件(nasm + gcc),特别是编译目标文件的依赖文件:本文旨在回顾 gcc 和 nams 编译器的编译命令,以及如果有多个依赖文件该如何编译: [1]编译文件 1.1)编 ...

  8. 使用T4模板为EF框架添加数据库实体注释

    网上有一个解决方法如下: http://www.cnblogs.com/stone_w/archive/2012/10/25/2738345.html 不过我试了下没解决太麻烦了 而且一旦EF要重新生 ...

  9. 用Newtonsoft将json串转为对象的方法(详解)

    首先,将json串转为一个JObject对象: JObject jo = (JObject)JsonConvert.DeserializeObject(CurrentSelectedItemReq) ...

  10. Python 之 安装模块的多种方法

    1.自己写的模块,能够直接加入到路径下. 这样就能够直接调用. import sys sys.path.append("/home/username/") 2.单文件模块 直接把文 ...