Java并发

来源:互联网 发布:慈溪锐智网络 编辑:程序博客网 时间:2024/06/16 01:59
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 {@NotThreadSafeclass UnsafeSequence {private int value;/** * <pre> * 如果执行时机不对,两个线程会在调用该方法的时候得到相同的值。 * @return * </pre> */public int getNext() {/** * value++; 不是单个操作,包含3个独立的操作: 读取value,将value加1,并将计算结果写入value */return value++;}}@ThreadSafeclass 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 {@Overridepublic void destroy() {}@Overridepublic ServletConfig getServletConfig() {return null;}@Overridepublic String getServletInfo() {return null;}@Overridepublic 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> */@ThreadSafeclass StatelessFactorizer extends BaseServlet {@Overridepublic 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> */@NotThreadSafeclass UnsafeCountingFactorizer extends BaseServlet {private long count = 0L;public long getCount() {return count;}@Overridepublic 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> */@NotThreadSafeclass LazyInitRace {private Object instance = null;public Object getInstance() {if (null == instance) {// 先判断后执行 --> 竞态条件instance = new Object();}return instance;}}/** * <pre> * @author kanpiaoxue * Date 2013-11-25 *  * 当在无状态的类中添加一个状态时,如果该状态完全由线程安全的对象来管理,那么这个类依然是线程安全的。 * </pre> */@ThreadSafeclass CountingFactorizer extends BaseServlet {private final AtomicLong count = new AtomicLong();public long getCount() {return count.get();}@Overridepublic 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;}}

0 0
原创粉丝点击