Spring事务管理的一些基础知识



| 
         1 
        2 
        3 
        4 
        5 
        6 
        7 
        8 
        9 
        10 
        11 
        12 
        13 
        14 
        15 
        16 
        17 
        18 
        19 
        20 
        21 
        22 
        23 
        24 
        25 
        26 
        27 
        28 
        29 
        30 
        31 
        32 
        33 
        34 
        35 
        36 
        37 
        38 
        39 
        40 
        41 
        42 
        43 
        44 
        45 
        46 
        47 
        48 
        49 
        50 
        51 
        52 
        53 
        54  | 
      
            //通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值。    private 
static ThreadLocal<Integer> tdLocal = new 
ThreadLocal<Integer>(){        public 
Integer initialValue(){            return 
0;        }    };         //获取下一个序列值。    public 
int getNextNum(){        tdLocal.set(tdLocal.get()+1);        return 
tdLocal.get();    }         //私有的测试线程类。    private 
static class TestClient extends 
Thread{        private 
SequenceNum seqNum;        public 
TestClient(SequenceNum seqNum){            this.seqNum = seqNum;        }        public 
void run(){            for(int 
i=0;i<3;i++){                System.out.println("Thread is ["                        + Thread.currentThread().getName() + "],序列号是  "                        + seqNum.getNextNum());            }        }    }              public 
static void main(String[] args) {        SequenceNum seqNum = new 
SequenceNum();        TestClient client1 = new 
TestClient(seqNum);        TestClient client2 = new 
TestClient(seqNum);        TestClient client3 = new 
TestClient(seqNum);        TestClient client4 = new 
TestClient(seqNum);        //运行线程。        client1.start();        client2.start();        client3.start();        client4.start();    }==================================================Thread is [Thread-1],序列号是  1Thread is [Thread-2],序列号是  1Thread is [Thread-0],序列号是  1Thread is [Thread-3],序列号是  1Thread is [Thread-3],序列号是  2Thread is [Thread-0],序列号是  2Thread is [Thread-2],序列号是  2Thread is [Thread-2],序列号是  3Thread is [Thread-1],序列号是  2Thread is [Thread-0],序列号是  3Thread is [Thread-3],序列号是  3Thread is [Thread-1],序列号是  3 | 
我们看到这四个线程共享了同一个SequenceNum实例,但是线程之间并没有相互的影响,而是各自产生独立的序列号,不存在线程安全性的问题,这是因为我们通过ThreadLocal为每一个线程提供了单独的变量副本。这也是Spring解决线程安全的机制。
????
书中有一句话很生动形象的对比了同步机制和ThreadLocal解决线程安全问题不同点:对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式:访问串行化,对象共享化;而ThreadLocal采用了“以空间换时间”的方式:访问并行化,对象独立化。前者提供一份变量,让不同的线程排队访问,而后者为每一份线程提供了一份变量,因此可以同时访问而互不影响。
Spring使用ThreadLocal解决线程安全的问题。
我们大概都有这么一个概念,只有无状态的Bean才能在多线程环境下共享,在Spring中,绝大部分的Bean都可以声明为singleton作用域。因为Spring对一些Bean(如RequestContextHolder,TranscationSynchronizationManager,LocalContextHolder)中非线程安全的“状态性对象”采用ThreadLocal进行封装,把他们变成线程安全的“状态性对象”,因此有状态的Bean能够以Singleton的方式在多线程中正常工作了。这里小可我说一下我的具体感受:原来Spring注入的JdbcTemplate是单例模式!其实就一个模板对象,把他注入到多个Service中,原来怎么没有注意到这一点呢?还有对有状态对象的理解,这个说的直白一点就是这个变量在不同的线程中不一样,尼玛取了一个有状态对象(变量)感觉好迷糊人啊!呵呵
看看书中对多线程的理解:
一般的Web应用划分为展现层、服务层和持久层三个层次,在不同的层中编写不同的逻辑,下次通过接口向上层开发接口调用。在一般的情况下,从接收请求到返回相应所经过的所有程序调用都同属于一个线程(看到这句话,我就想到了Servlet和CGI的区别,一个请求到来Servlet就会新建一个线程去响应这个请求,而CGI则是需要新建一个进程,所以Servlet的效率更高。尼玛这是以前看过的一个面试题啊,终于对上了),如图:
这样根据需要,把一些非线程安全的变量存放到ThreadLocal中,在同一次请求响应的调用线程中,所有对象访问同一ThreadLocal变量都是当前线程绑定的。
怎么理解Spring中DAO和Service都是以单实例的bean形式存在这句话,就是不同的线程调用的都是同一个DAO和Service的实例,只有一个实例。
http://blog.csdn.net/c289054531/article/category/1473443 
    
原文:http://www.cnblogs.com/lovery/p/3745712.html