并发编程-线程

120 阅读3分钟

前言

当JVM启动时,会为内部任务,比如垃圾收集,创建后台线程,并创建一个主线程来执行main方法。所以,Java程序都是多线程的。

作为一个Java开发工程师,你不可避免地必须了解线程,必须熟悉多线程开发的优势以及引入的风险。

由来

摘自百度百科

60年代,在OS中能拥有资源和独立运行的基本单位是进程,然而随着计算机技术的发展,进程出现了很多弊端,一是由于进程是资源拥有者,创建、撤消与切换存在较大的时空开销;二是由于对称多处理机(SMP)出现,可以满足多个运行单位,而多个进程并行开销过大。

因此在80年代,出现了能独立运行的基本单位——线程(Threads)。

简而言之,线程是为了解决进程的弊端产生的。

基本概念

定义

线程是操作系统调度的基本单位,共享进程范围内的资源。

进程与线程的关系

  1. 进程是操作系统资源分配的基本单位,线程是操作系统调度的基本单位
  2. 一个进程包括多个线程
  3. 进程间相互独立,线程间共享进程范围内的资源
  4. 线程的调度和上下文切换比进程快

线程共享的资源

  • 文件句柄
  • 内存句柄
  • ...

线程私有的资源

  • 程序计数器
  • 函数调用栈
  • 局部变量
  • ...

优势

发挥多处理器的强大能力

如今单芯片多核CPU已经相当普及,设计正确的多线程程序可以通过提高处理器利用率来提升系统吞吐率。另外,使用多线程还有助于在单处理器系统上获得更高的吞吐率,例如某个线程在等待IO操作完成时,处理器是空闲的,此时处于就绪态的线程是可以执行的。在进行多线程编程时,要根据任务特征综合考虑这两个特性。

简化建模

通过多线程,可以将复杂且异步的工作流分解为一组简单且同步的工作流,每个工作流在一个单独的线程中执行,并在特定的同步位置进行交互。

异步事件的简化处理

比如服务端程序处理客户端的连接请求,使用一个主程序接受连接请求,连接成功之后使用单独的线程进行通信,可以大大降低这类程序的开发难度。

响应更灵敏的GUI

大多数GUI框架都是单线程子系统,事件线程会监听界面事件,执行相应的任务,如果任务是耗时的,那么界面会阻塞无响应;对于这类任务,可以使用单独的后台任务执行,这样事件线程就可以继续及时地处理界面事件,使用户界面有更高的灵敏性。

风险

线程是一把双刃剑,有利也有弊。

安全性问题

在多线程环境下,没有足够的同步机制,程序运行的结果是不可预测的。

安全性问题往往由下面三个因素之一或者组合导致:

  • 原子性
  • 可见性
  • 有序性

活跃性问题

  • 死锁
  • 饥饿
  • 活锁
  • ...

性能问题

  • 上下文切换
  • ...