Java并发编程实战

import com.wanmei.parallel.concurrency.help.NotThreadSafe;
import com.wanmei.parallel.concurrency.help.ThreadSafe;

/**
 * <pre>
 * @author kanpiaoxue
 * Date 2013-11-25
 * 
 * 		第一部分:基础知识
 * 		第一章:简介
 * 一、介绍:
 * 线程允许在同一个进程中同时存在多个程序控制流。
 * 由于同一个进程中的所有线程都将共享进程的内存地址空间,因此这些线程都能访问相同的变量并在同一个堆上分配对象,
 * 这就需要实现一种比在进程间共享数据粒度更细的数据共享机制。如果没有明确的同步机制来协同对共享数据的访问,
 * 那么当一个线程正在使用某个变量时,另一个线程可能同时访问这个变量,这将造成不可预测的结果。
 * 二、线程的优势:
 * 1、发挥多处理器的强大能力
 * 2、建模的简单性
 * 3、异步事件的简化处理
 * 4、响应更灵敏的用户界面
 * 三、线程带来的风险:
 * 1、安全性问题
 *   要使多线程程序的行为可以预测,必须对共享变量的访问操作进行协同,这样才不会在线程之间发生彼此干扰。
 * 2、活跃性问题
 *   “某件正确的事情最终会发生”。当某个操作无法继续执行下去时,就会发生活跃性问题。
 * 3、性能问题
 * 
 * </pre>
 */
public class Chapter01 {

	@NotThreadSafe
	class UnsafeSequence {
		private int value;

		/**
		 * <pre>
		 * 如果执行时机不对,两个线程会在调用该方法的时候得到相同的值。
		 * @return
		 * </pre>
		 */
		public int getNext() {
			/**
			 * value++; 不是单个操作,包含3个独立的操作: 读取value,将value加1,并将计算结果写入value
			 */
			return value++;
		}
	}

	@ThreadSafe
	class Sequence {
		private int value;

		public synchronized int getNext() {
			return value++;
		}
	}

}

 

import java.io.IOException;
import java.math.BigInteger;
import java.util.concurrent.atomic.AtomicLong;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import com.wanmei.parallel.concurrency.help.NotThreadSafe;
import com.wanmei.parallel.concurrency.help.ThreadSafe;

/**
 * <pre>
 * @author kanpiaoxue
 * Date 2013-11-25
 * 
 * 		第一部分:基础知识
 * 		第二章:线程安全性
 * 在构建稳健的并发程序时,必须正确地使用线程和锁。
 * 要编写线程安全的代码,其核心在于要对状态访问操作进行管理,特别是对共享的和可变的状态的访问。
 * 
 * --------------------------------------
 * 如果当多个线程访问同一个可变的状态变量时没有使用合适的同步,那么程序就会出现错误。
 * 有三种方式可以修复这个问题:
 * 1、不在线程之间共享该状态变量。
 * 2、将状态变量修改为不可变的变量。
 * 3、在访问状态变量时使用同步。
 * --------------------------------------
 * 当设计线程安全的类时,良好的面向对象技术、不可修改性,以及明晰的不变性规范都能起到一定的帮助作用。
 * --------------------------------------
 * 在编写并发应用程序时,一种正确的编程方法是:
 * 首先使代码正确运行,然后再提高代码的速度。
 * 即便如此,最好也只是当性能测试结果和应用需求告诉你必须提高性能,以及测量结果表明这种优化在实际环境中确实能带来性能提升时,才进行优化。
 * --------------------------------------
 * 1、什么是线程安全性
 * 线程安全性最核心的概念是:正确性。
 * 当多个线程访问某个类时,这个类始终都能表现出正确的行为,那么这个类是“线程安全的”。
 * 在线程安全的类中封装了必要的同步机制,因此客户端无需进一步采取同步措施。
 * --------------------------------------
 * 无状态对象一定是线程安全的。
 * --------------------------------------
 * 2、原子性
 * 	a、竞态条件:在并发编程中,由于不恰当的执行时序而出现不正确的结果是一种非常重要的情况,它就是竞态条件。
 *  	当某个计算的正确性取决于多线程的交替执行时序时,那么就会发生竞态条件。
 *  	最常见的竞态条件类型就是:“先检查后执行(Check-Then-Act)”操作,即通过一个可能失效的观测结果来决定下一步的动作。
 *  b、延迟初始化中的竞态条件: LazyInitRace
 *  c、复合操作:
 *  	假定有两操作A和B,如果从执行A的线程来看,当另一个线程执行操作B时,要么将B全部执行完,要么完全不执行B,
 *  那么A和B对彼此来说就是原子的。
 *  “原子操作”是指:对于访问同一状态的所有操作(包括该操作本身)来说,这个操作是一个以原子方式执行的操作。
 *  CountingFactorizer
 * 3、加锁机制
 * 	要保持状态的一致性,就需要在单个原子操作中更新所有相关的状态变量。
 * a、内置锁
 * 	Java提供一种内置的锁机制来支持原子性:synchronized
 * b、重入
 * 
 * 	4、用锁来保护状态
 * --------------------------------------
 * 对于可能被多个线程同时访问的可变状态变量,在访问它时都需要持有同一个锁,在这种情况下,我们称状态变量是有这个锁保护的。
 * --------------------------------------
 * 每个共享的和可变的变量都应该只由一个锁来保护,从而使维护人员知道是哪一个锁。
 * --------------------------------------
 * 并非所有数据都需要锁的保护,只有被多个线程同时访问的可变数据才需要通过锁来保护。
 * --------------------------------------
 * 对于每个包含多个变量的不变性条件,其中涉及的所有变量都需要由同一个锁来保护。
 * --------------------------------------
 *  5、活跃性与性能
 *  	最好不要在整个方法上使用 synchronized,而是要对尽可能短的代码路径进行同步。这样就会获得更好的并发性能。
 *  	对在单个变量上面实现原子操作来说,原子变量是很有用的( AtomicLong )。但是如果已经采用了同步代码块 synchronized 来构造原子操作,
 *  而使用两种不同的同步机制不仅会带来混乱,也不会在性能或安全性上带来任何好处,因此这里不使用原子变量。
 * --------------------------------------
 * 通常,在简单性与性能之间存在着相互制约因素。当实现某个同步策略时,一定不要盲目的为了性能而牺牲简单性(这可能会破坏安全性)。
 * --------------------------------------
 * 当执行时间较长的计算或者可能无法快速完成的操作时(例如,网络I/O或控制台I/O),一定不要持有锁。
 * --------------------------------------
 * </pre>
 */
public class Chapter02 {

	abstract class BaseServlet implements Servlet {

		@Override
		public void destroy() {
		}

		@Override
		public ServletConfig getServletConfig() {
			return null;
		}

		@Override
		public String getServletInfo() {
			return null;
		}

		@Override
		public void init(ServletConfig arg0) throws ServletException {
		}

		public abstract void service(ServletRequest arg0, ServletResponse arg1)
				throws ServletException, IOException;
	}

	/**
	 * <pre>
	 * @author kanpiaoxue
	 * Date 2013-11-25
	 * 
	 * 给出了一个简单的因数分解Servlet。这个Servlet从请求中提取出数值,执行因数分解,然后将结果封装到该servlet的响应中。
	 * 一个无状态的Servlet:
	 * 	它记不包含任何域,也不包含任何对其他类中域的引用。
	 * 	计算过程中的临时状态仅存在于线程栈上的局部变量中,且只能由正在执行的线程访问。
	 * </pre>
	 */
	@ThreadSafe
	class StatelessFactorizer extends BaseServlet {

		@Override
		public void service(ServletRequest req, ServletResponse resp)
				throws ServletException, IOException {
			BigInteger i = extractFromRequest(req);
			BigInteger[] factors = factor(i);
			encodeIntoResponse(resp, factors);
		}

	}

	/**
	 * <pre>
	 * @author kanpiaoxue
	 * Date 2013-11-25
	 * 
	 * 假设我们希望添加一个“命中计数器”来统计所处理的请求数量。
	 * </pre>
	 */
	@NotThreadSafe
	class UnsafeCountingFactorizer extends BaseServlet {
		private long count = 0L;

		public long getCount() {
			return count;
		}

		@Override
		public void service(ServletRequest req, ServletResponse resp)
				throws ServletException, IOException {
			BigInteger i = extractFromRequest(req);
			BigInteger[] factors = factor(i);
			++count;// 这里不是原子操作,是非线程安全的。
			encodeIntoResponse(resp, factors);
		}

		private void encodeIntoResponse(ServletResponse resp,
				BigInteger[] factors) {

		}

		private BigInteger[] factor(BigInteger num) {
			return null;
		}

		private BigInteger extractFromRequest(ServletRequest req) {
			return null;
		}
	}

	/**
	 * <pre>
	 * @author kanpiaoxue
	 * Date 2013-11-25
	 * 
	 * 这个类包含一个“竞态条件”,可能破坏这个类的正确性。
	 * 它是“非线程安全”的。
	 * </pre>
	 */
	@NotThreadSafe
	class LazyInitRace {
		private Object instance = null;

		public Object getInstance() {
			if (null == instance) {// 先判断后执行 --> 竞态条件
				instance = new Object();
			}
			return instance;
		}

	}

	/**
	 * <pre>
	 * @author kanpiaoxue
	 * Date 2013-11-25
	 * 
	 * 当在无状态的类中添加一个状态时,如果该状态完全由线程安全的对象来管理,那么这个类依然是线程安全的。
	 * </pre>
	 */
	@ThreadSafe
	class CountingFactorizer extends BaseServlet {
		private final AtomicLong count = new AtomicLong();

		public long getCount() {
			return count.get();
		}

		@Override
		public void service(ServletRequest req, ServletResponse resp)
				throws ServletException, IOException {
			BigInteger i = extractFromRequest(req);
			BigInteger[] factors = factor(i);
			count.incrementAndGet();
			encodeIntoResponse(resp, factors);

		}
	}

	private void encodeIntoResponse(ServletResponse resp, BigInteger[] factors) {

	}

	private BigInteger[] factor(BigInteger num) {
		return null;
	}

	private BigInteger extractFromRequest(ServletRequest req) {
		return null;
	}

}

 

你可能感兴趣的:(Java并发编程)