Java并发编程实战笔记

多线程简介

 ->为什么要编写并发程序?
    能使复杂的异步代码变得更简单(从而极大地简化了复杂系统的开发);
    充分发多处理器系统的强大计算能力。
  ->并发概述:
    ·操作系统的出现使得计算机每次能运行多个程序,并且不同的程序都在单独的进程中运行:
      操作系统为各个独立执行的进程分配各种资源(内存、文件句柄、安全证书等)
      进程之间的粗粒度通信(套接字、信号处理器、共享内存、信号量以及文件等)
    ·多程序并发执行的原因:
      资源利用率:在等待执行的同时可以运行另一个程序,可以提高资源利用率;
      公平性:不同用户和程序对于计算机上的资源有同等使用权(通过粗粒度的时间分片使这些用户和程序能共享计算机资源)
      便利性:计算多个任务时(可以编写多个程序,每个程序执行一个任务并在必要时相互通信,这比只编写一个程序来计算所有任务更容易实现)
    ·由于基本的调度单位是线程,因此如果在程序中只有一个,则最多同时只能在一个处理器上运行(在拥有100个处理器的系统上,将有99%的资源无法使用)
    ·安全性问题:(示例:非线程安全的数值序列生成器)
@NotThreadSafe
public class UnsafeSequence {
	private int value;

	//返回一个唯一的数值
	public int getNext() {
	  return value++;
	}
}
      UnsafeSequence.getNext()的错误执行情况:(A、B两线程交替执行的示意图)
	      A: value->9; 9+1->10; value=10
	      B:  value->9; 9+1->10; value=10
	  UnsafeSequence类中说明的是一种从常见的并发安全问题,称为竞态条件。(由于多个线程要共享相同的内存地址空间,并且是并发运行,因此它们可能会访问或修改其他线程正在使用的变量)
	  通过将getNext修改为一个同步方法,可以修复UnsafeSequence中的错误:
@ThreadSafe
public class Sequence {
	@GuardedBy("this") private int Value;

	public synchronized int getNext() {
	  return Value++;
	}
}
    ·活跃性问题:(线程A在等待线程B释放其持有的资源,....死锁,你懂的)
    ·性能问题:...
    ·线程无处不在:
      每个Java应用程序都会使用线程(当JVM启动时,它将为JVM的内部任务,例如垃圾收集、终结操作等创建后台进程,并创建一个主线程来运行main方法。)

线程安全性

  ·当多个线程访问某个状态变量并且其中有一个线程执行写入操作时,必须采用同步机制来协同这些线程对变量的访问。Java中的主要同步机制是关键字synchronized,它提供了一种独占的加锁方式,但“同步”这个术语还包括volatile类型的变量、显示锁(Explicit Lock)以及原子变量。
  ·若当多个线程访问同一个可变的状态变量时没有使用合适的同步,则程序就会出现错误。有以下三种方式可以修复这个问题:
    ·不在线程之间共享该状态变量;
    ·将状态变量修改为不可变的变量;
    ·在访问状态变量时使用同步。
  ·当设计线程安全的类时:良好的面向对象技术、不可修改性以及明晰的不变性规范都能起到一定帮助作用。
  ->什么是线程安全性?
    在线程安全性的定义中,最核心的概念就是正确性;
    正确性:某个类的行为与其规范完全一致。规范不常有,所以用以描述单线程正确性近似定义为“所见即所知(we know it when we see it)”。
    定义:当多个线程访问某个类时,这个类始终都能表现出正确的行为,则称这个类是线程安全的。(不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为)
    ·在线程安全类中封装了必要的同步机制,因此客户端无须进一步采取同步措施。
    示例:一个无状态的Servlet
@ThreadSafe
public class StatelessFactorizer implements Servlet {
	public void service(ServletRequest req, ServletResponse resp) {
	  BigInteger i = extractFromRequest(req);
	  BigInteger[] factors = factor(i);
	  encodeIntoResponse(resp, factors);
	}
}
      上面的这个类是无状态的(既不包含任何域、也不包含对其他类中域的引用)
      所以,计算过程中的临时状态仅存在于线程栈上的局部变量中,并且只能由正在执行的线程访问。
      ->无状态对象一定是线程安全的。(大多数Servlet都是无状态的,只有当Servlet在处理请求时需要保存一些信息,线程安全性才会成为一个问题)
  ->原子性

你可能感兴趣的:(Java后端架构)