Java并发
2016-01-06 15:19
477 查看
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 Socket 获取本地主机ip
- Java——属性接口返回json数据
- 使用Java对文件或文件夹的压缩, 解压, 加密和解密
- 多线程基础及实例(java)
- eclipse 重新关联源码方式
- java 并发编程
- Java ——基础之继承与接口的区别
- java反射讲解实例
- JDK中rt.jar、tools.jar和dt.jar的理解
- Spring学习总结(6)——Spring之核心容器bean
- spring从文件系统载入配置文件
- Struts2注解开发
- java学习笔记参考
- java 获取唯一订单号;
- Spring学习总结(5)——IOC注入方式总结
- java24.线程------实现
- JAVA线程池中的Callable和Future
- JAVA中使用FTPClient上传下载
- java后台开发- NOTE
- Java web开发(1)