多线程-第二天

来源:互联网 发布:淘宝无线端是什么意思 编辑:程序博客网 时间:2024/05/16 23:47

只有一个状态的类的线程安全性

  1. 无状态的对象,一定是线程安全的。

    无状态:不包括任何域,也不包含任何对其它类中域的引用。

  2. 兑态条件(Race condition):由于不恰当的执行顺序而出现的不正确的结果。

    先检查后执行(check-then-act):通过一个可能失效的观测结果来执行下一步的动作。

    星巴克找人的例子;
    延迟初始化中的竞态条件;
    i++;

//延迟初始化中的竞态条件@NotThreadSafepublic class LazyInitRace{    private ExpensiveObject = null;    private ExpensiveObject getInstance(){        if(instance == null){            instance = new ExpensiveObject();        }        return instance;    }}           

数据竞争:如果在访问非共享的非final类型的域时没采用同步来进行协同,那么就会引起数据竞争。与竞态条件是有区别的。请从定义区分。

对于资源(变量)的修改需要以原子的方式执行,防止其它线程使用这个资源(变量),才能保证修改数据的安全性。

复合操作

  • 先检查后执行、『读取-修改-写入』(i++)操作,
  • 线

线程安全的自增操作

//AtomLong类型的变量,保证自增的原子性@ThreadSafepublic class CountingFactorizer implement Servlet {    private final AtomicLong count = new AtomicLong(0);    public long getCount(){return count;}    public void service(ServletRequest req, ServletResponse resp){        BigInteger i = extractFromRequest(req);        BigInteger[] factors = factor[i];        count.IncrementAndGet();        encodeIntoResponse(resp, factors);    }}       

在无状态中的类中增加一个状态时,如果这个状态由线程安全的类来管理,那个这个类是线程安全的,但是有多个状态时,却不是这么简单的。
应该尽可能的使用现有的线程安全的对象,如AtomicLong。

有多个状态的类的线程安全性

通过加锁机制实现。
要保持状态的一致性,就要在单个原子操作中更新所有相关的状态变量。

1.内置锁:synchronized代码块

包括两部分:一个作为锁的对象引用,一个作为这个锁保护的代码块。
synchronized
synchronizedClass

每个java对象都可以用作一个实现同步的锁,被称为内置锁(Intrinsic lock)或监视锁(Monitor Lock)。

//分解质因数的servlet,并发性非常糟糕@ThreadSafepublic class SynchronizedFactorier implements Servlet{    @GardedBy("this") private BigInteger lastNumber;     @GardedBy("this") private BigInteger[] lastFactories;    public synchronized void service(ServletRequest req, ServletResponse resp) {        BigInteger i = extractFromRequest(req);        if(i.equals(lastNumber)){            encodeIntoResponse(resp, lastFactories);        }else {            BigInteger[] factors= factor(i);            lastNumber = i;            lastFactors = factors;            encodeIntoResponse(resp, factories);        }    }}               

这个程序的缺点是只能有一个线程执行service方法,效率很低,但是确实是线程安全的。

2.重入

一个线程请求他自己持有的锁,就会成功。
获取锁的操作粒度是『线程』而非『调用』。
实现方法是,为每个锁关联一个获取计数值和所有者线程。
不可重入将导致子类无法调用父类中的同步(synchronized)方法,出现死锁。

3.用锁来保护状态

锁能够使其保护的代码以串行方式访问。
对象的内置锁与其状态之间没有内在的关联。
synchronized使用的是对象的内置锁,是可重入的。可重入的锁,有自动的计数。
每个对象都有一个内置锁。
一种常见的加锁约定是,将每个可变的状态都放在一个对象中,并通过对象的内置锁对所有访问可变状态的代码路径进行同步,使得该对象上不会发生并发访问。
再声明一次,竞态条件,就是后面语句的执行,会依赖前面语句的结果,当然是在多线程的环境中。
将类中的每个方法都声明为synchronized会带来活跃性和性能问题。

4.活跃性(liveness)与性能(performance)

要确保同步代码块不要过小,并且不要将原子操作拆分到多个同步代码块中。应该尽量将不影响共享状态且执行时间较长的操作从同步代码块中分离出去,从而在这些操作的执行过程中,其它线程可以访问共享状态。

当执行时间长的计算或者可能无法快速完成的操作时,一定不要持有锁。

线程中的局部变量是不需要同步操作的,因为与其它线程之间没有共享状态。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 月季花夏天换盆出现黄叶怎么办 刚种的月季枯了怎么办 新买的月季黄叶了怎么办 月季花叶孑轰发黄怎么办? 新种的月季苗弱怎么办? 月季换盆后浇透水叶子黄了怎么办 肉肉移栽后浇透水怎么办 月季花扦插的没长根发芽了怎么办 君子兰发的小苗怎么办 蔷薇光长枝条不开花怎么办 牡丹发芽又干了怎么办 擦皮炎平后皮肤变黑怎么办 误喝发霉的咖啡渣怎么办 狗吃了速溶咖啡怎么办 咖啡机放豆的地方进水怎么办 干吃咖啡粉上瘾怎么办 去良友花艺住宿怎么办 充气娃娃放了气怎么办 煮杜鹃根没有锅怎么办 淘宝店卖鲜花被买家拒收货怎么办 执业医师电子注册忘记密码怎么办 怀孕吃了油炸的怎么办 百合长得太高怎么办 百合的杆没了怎么办 百合花长得太细怎么办 沙漠玫瑰的花苞打不开怎么办 鲜切花 较小的花苞怎么办 大棚玫瑰苗水大涝的不长怎么办 鲜花买回来蔫了怎么办 喝玫瑰醋上火了怎么办 插在花泥上的花怎么办 插的花蔫了怎么办 紫睡莲的茎软了怎么办 家养的荷花烂叶怎么办 家养的荷花叶老是枯萎怎么办 新买的绣球蔫了怎么办 绣球花被太阳晒阉了怎么办 羊肉香精放多了怎么办 被飞机防腐剂弄到皮肤怎么办 狗吃了脱氧保鲜剂呕吐怎么办 小孩误吃试纸了保鲜剂怎么办