java并发编程《一》介绍

1,并发的简短历史

1,OS的发展使多个程序同时运行,程序在各自的进程(process)中运行:相互分离,各自独立执行,有OS来分配资源,比如内存,文字句柄,安全证书。如果有需要的话,进程会通过一些原始的机制相互通信:Socket,signal handlers,shared memory,semaphores和文件
2,推动OS支持多程序同时执行发展的因素
a:资源利用。程序有时候需要等待外部操作,比如输入和输出,并且在等待的时候不可能进行有价值的工作。在等待的时候,让其他的程序运行会提高效率
b:公平。多个用户或程序可能对系统资源有平等的优先级别。让他们通过更好的时间片方式来共享计算机
c:方便。写一些程序,让他们各自执行一个单独的任务并进行必要的相互协调,这要比编写一个程序来执行所有的任务更加容易
3,冯诺依曼机(von Neumann):拥有一个内存空间,储存着着指令和数据,根据机器语言的语义来顺序地执行指令,并且通过OS的I/O原语集来实现与外部世界的交互。对于每一条执行的执行都有一个对“下一条指令”的明确定义,并根据程序中的指令集进行流程控制。
4,顺序编程模型是自然的,常规的就像遵守着人类的工作方式:一次做一件事情,顺序进行

5,相同的关注点(1.2中的a,b,c)不仅促进了进程的发展,也促进了线程的发展。线程允许程序控制流(control flow)的多重分支同时存在于一个进程。它们共享进程范围内的资源,比如内存和文件句柄,但是每一个线程有起自己的程序计数器(program counter),栈(stack)和本地变量。线程 也为多处理系统中并行地使用硬件提供了一个自然而然的分解,同一个程序内的多个线程可以在多cpu的情况下同时调度。
6,线程有些时候被称为轻量级进程,并且大多数操作系统把线程作为时序的调度的基本单元,而不是进程。在没有明确协调的情况下,线程相互间同时或异步的执行,因为共享其所属进程的内存地址空间,因此所有同一进程中相乘访问相同的变量,并从同一堆中分配对象,这相对于进程间通信机制来说实现良好的数据共享

2,线程的优点

1,可以降低开发和维护的开销
2,提高复杂应用的性能
3,可以把复杂,难以理解的代码转化为直接,简洁的代码,这样更加读写及维护
4,线程在GUI Application中是非常有用的,可以改进用户接口的响应性,并且在服务器中,用于提高资源的利用率和吞吐量。
5,简化JVM的实现,垃圾收集器通常运行于一个或多个持续的工作线程之间

###2.1,使用多处理器
注意:处理器很难提高它的时钟频率,处理器厂商会在一个芯片上放置更多的处理器内核。一个单线程的app一次只能运行在一个处理器上
在设计良好的情况下,多线程程序通过更有效的利用空闲的处理器资源,来提高吞吐量,也可以在单处理器上实现更加的吞吐量,如果一个程序是单线程的,这个处理器在等待一个同步I/O操作完成的时候,仍然是空闲的。在多线程中当第一个线程等待I/O结束的同时,另一个线程也可以运行,这样就使得应用程序在遇到I/O阻塞的时候仍然有进展
###2.2,模型的简化
一个复杂,异步的流程可以被分解为一系列简单同步流程,它们中每一个相互独立的线程中运行,只有在特定同步点才进行彼此间的交互
###2.3,对异步事件的简单处理
###2.4,用户界面的更佳响应性

3,线程的风险

java对线程内置的支持是一把双刃剑,它通过提供语言和类库,以及一个规范的跨平台存储模型,简化并发应用开发。线程安全的问题
###3.1,安全危险
线程安全问题是出乎意料的,因为在没有进行充分同步的情况下,多线程中的各个操作是不可预测的,biqu

@NotThreadSafe
public class UnsafeSequence {
    private int value;
    /**
     *    返回一个唯一的值
     */
    public int getNext() {
        return value++;
    }
}

在这里插入图片描述
UnsafeSequence 的问题是;在一些特殊的时序情况下,两个线程可以调用getNext()并得到相同的返回值 ,图1.1表现了如何发生的,value++:读取这个值,使之加1,再写入新值;所以两个线程都肯同时读取这个值,两个线程得到相同的值,并都使之增加1.结果就是返回了相同序列数。
UnsafeSequence阐明了一种常见的并发危险:竞争条件。当被多线程调用的时候,getNext是否能返回不重复的值,
因为线程共享相同的内存地址空间,且并发的运行,它们可能访问或修改其他线程正在使用的变量。这是非常方便的,因为它使得数据共享相对于其他的线程间通信机制更加简单。风险是:当数据意外改变的时候,线程可能会发生混乱。允许许多线程访问和修改相同的变量,给顺序编程模型引入一些非顺序因素,这可能会做成混乱,并且难以发现错误。
可以通过把getNext()声明为synchronize类型的方法来修正UnsafeSequence
线程安全的序列生成器

@ThreadSafe
public class UnsafeSequence {
    @GuardedBy("this") private int value;
    /**
     *    返回一个唯一的值
     */
    public synchronized int getNext() {
        return value++;
    }
}

注意:在缺少同步的时候,编译器,硬件和运行时对时间和活动顺序时很随意的,比如在寄存器或者高速缓存中存储变量,这样会使它们对于其他线程暂时不可见,这被认为提高性能的非常可行的方法,但是对开发人员来说,他们需要明确识别数据在线程中使究竟如何共享的,这样的优化才不至于破坏安全

###3.2,活跃度的危险
当一个活动进入某种它永远无法再继续执行的状态时,活跃度失败就发生了。一种活跃度失败可以发生在顺序程序中,这就是粗心造成的无限循环,那些循环之后的代码永远不会执行。多线程的引入带来更多活跃度危险。例如,如果线程A等待线程B独立占有的资源,B永远不是释放这个资源,A将永远等待下去。(引起活跃度失败的bug很难发现,因为取决于线程间相关的事件时序)
###3.3,性能的危险
性能问题涉及很多方面包括服务时间,响应性,吞吐量,资源消费或者可伸缩性的不良表现。
a,上下文切换(Context switches):当调度程序临时挂起当前运行的线程时,另一个线程开始运行-这在多线程组成的应用程序重视很频繁的,并且带来巨大的系统开销:保存和恢复线程执行的上下文,离开执行现场,并且CPU的时间花费在对线程的调度而不是在运行上。
b,当线程共享数据的时候,它们必须使用同步机制,这个机制会限制编译器的优化,能够清空或锁定内存和高速缓存,并且在共享内存总线上创建同步通信

4,线程无处不在

###4.1,即时你的程序没有显示的创建任何线程,框架也可能为创建一些线程,这些线程调用的代码必须是线程安全的(thead safe)(注意线程安全的类比非线程安全的类更加的仔细,进行更多分析)

###4.2,线程安全的需要并不仅仅在于框架调用的组件----只要它处于组件访问过的程序状态段,他就会扩展到所有的代码路径,因此,线程安全需要是具有传递性
注意:通过从框架线程中调用应用程序的组件,框架把并发引入应用程序。组件总是需要访问程序的状态。因此要求在所有代码路径访问状态时,必须是线程安全的。
以下描述的这些场景,都会引发非应用程序管理调用应用程序代码这种情况下,当需要线程安全的时候,可能会以这样的情况作为开始,可以这样做几乎都不能正常结束:反而会影响到整个程序。
1,定时器。Timer用来调度一些稍后运行的任务也可以是只运行一次或者周期性运行的任务,这是一种非常方便的机制。
注意:引入Timer可以使一个通常简单的顺序程序变得复杂
因为TimerTasks运行在由Timber管理的线程中,并不是由应用程序来管理。如果一个TimerTasks访问其他应用程序线程正在访问的数据,那么不仅TimerTask需要线程安全的手段,并且其他那些同时访问这个数据的类也需要相应的措施。通常最简单的实现方法是确保TimerTask访问的对象本身是线程安全的,因此将线程安全封装到共享对象的内部
2,Servlets and JavaServer Pages(JSPs)Servlets框架的涉及目的是处理Web应用的部署,分发来自远程HTTP客户的请求这些的基础层业务 。Servlets的规范规定了一个Servlet必须为多个用户同时调用它做好准备。换句话说Servlets应该是线程安全的
3,Remote Method Invocation使你能够调用在另外一个JVM上运行的对象的方法。当你使用RMI调用一个远程方法时,这个方法参数被装配成一个比特流,并且穿越整个网络到达远程JVM,在那里它会被解包并传递给远程方法
当RMI代码调用了你的远程对象时,这个调用发生在哪一个线程?你并不知道,但绝不是你创建的那个线程------你的对象被RMI管理的一个线程所调用。
一个远程对象必须守卫两种线程安全风险,对那些肯尼会域其他对象共享的状态进行适当的调节,应正确的对远程对象本身进行调控(因为相同的对象可能同时被多个线程调用),

4,Swing和AWT GUI应用程序具有固有的异步特性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大道至简@EveryDay

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值