zoukankan      html  css  js  c++  java
  • Java 线程第三版 第五章 极简同步技巧 读书笔记



    一、能避免同步吗?

    取得锁会由于下面原因导致成本非常高:
        取得由竞争的锁须要在虚拟机的层面上执行很多其它的程序代码。
        要取得有竞争锁的线程总是必须等到锁被释放后。


    1. 寄存器的效应

    计算机有一定数量的主寄存器用来存储与程序有关的数据。


    从逻辑上的观点来看,每一个Thread都有自己的一组寄存器。当操作系统将某个Thread分配给CPU时,它会把该Thread特有的信息载入到CPU的寄存器中。

    在分配不同的Thread给CPU之前,它会将寄存器的信息存下来。

    所以Thread间绝不会共享保存在寄存器的数据。


    当虚拟机进入synchronized方法或者块时。它必须又一次载入本来已经缓存到自有寄存器上的数据。在虚拟机离开synchroized方法或者块之前,它必须把自有寄存器存入主寄存器中。




    2. 重排语句的效应

    在单独线程中。程序总是依照代码一行行的运行的。可是假设是多个线程并发,Java并不保证每一个线程run方法的运行顺序,也就是可能当中一个线程运行到一半就会被临时停止。运行其它线程,之后再切换回来。


    多个线程间调度运行的无序性就是重排语句的效应。




    3. 双重检查的Locking


    二、Atomic变量

    1. Atomic Class的概述

        AtomicInteger, AtomicLong, AtomicBoolean, AtomicRefrences。Atomic的功能实现时通过使用use-level的Java程序无法訪问的固有方法来完毕的。
    atomic package支持更复杂的变量类型吗?


        一些不支持。比如字符或者浮点。
        AtomicStampedReference可以让mark或stamp跟在不论什么对象的引用上。
        AtomicMarkableReference提供一个包括对象引用结合boolean的数据结构。




    2. 使用Atomic Class

    import javax.swing.*;
    import java.awt.event.*;
    import java.util.concurrent.*;
    import java.util.concurrent.atomic.*;
    import javathreads.examples.ch05.*;
    
    public class ScoreLabel extends JLabel implements CharacterListener {
        private AtomicInteger score = new AtomicInteger(0);
        private AtomicInteger char2type = new AtomicInteger(-1);
        private AtomicReference<CharacterSource> generator = null;
        private AtomicReference<CharacterSource> typist = null;
    
        public ScoreLabel (CharacterSource generator, CharacterSource typist) {
            this.generator = new AtomicReference(generator);
            this.typist = new AtomicReference(typist);
    
            if (generator != null)
                 generator.addCharacterListener(this);
            if (typist != null)
                 typist.addCharacterListener(this);       
        }
    
        public ScoreLabel () {
            this(null, null);
        }
    
        public void resetGenerator(CharacterSource newGenerator) {
            CharacterSource oldGenerator;
    
            if (newGenerator != null)
                newGenerator.addCharacterListener(this);
    
            oldGenerator = generator.getAndSet(newGenerator);
            if (oldGenerator != null)
                oldGenerator.removeCharacterListener(this);
        }
    
        public void resetTypist(CharacterSource newTypist) {
            CharacterSource oldTypist;
    
            if (newTypist != null)
                newTypist.addCharacterListener(this);
    
            oldTypist = typist.getAndSet(newTypist);
            if (oldTypist != null)
                oldTypist.removeCharacterListener(this);
        }
    
        public void resetScore() {
            score.set(0);
            char2type.set(-1);
            setScore();
        }
    
        private void setScore() {
            // This method will be explained later in chapter 7
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    setText(Integer.toString(score.get()));
                }
            });
        }
    
        public void newCharacter(CharacterEvent ce) {
            int oldChar2type;
     
            // Previous character not typed correctly - 1 point penalty
            if (ce.source == generator.get()) {
                oldChar2type = char2type.getAndSet(ce.character);
    
                if (oldChar2type != -1) {
                    score.decrementAndGet();
                    setScore();
                }
            }
            // If character is extraneous - 1 point penalty
            // If character does not match - 1 point penalty
            else if (ce.source == typist.get()) {
                while (true) {
                    oldChar2type = char2type.get();
    
                    if (oldChar2type != ce.character) {
                        score.decrementAndGet();
                        break;
                    } else if (char2type.compareAndSet(oldChar2type, -1)) {
                        score.incrementAndGet();
                        break;
                    }
                }
    
                setScore();
            }
        } 
    }
    




    变量替换
    score与char2type变量已经改成atomic变量。
    以上resetScroe方法中对两个变量进行改动。尽管使用atomic能保证每一个变量的原子性,可是假设多个线程同一时候运行resetScore方法依旧会出现竞态条件。
    有可能一个线程运行resetScore的第一行代码score.set(0);还未运行第二行,而另外一个线程可能已经运行newCharacter方法获取char2type的值,可是之前的线程运行resetScore方法还未对char2type进行改动。由于resetScore整个方法并非原子的。


    变更算法
    resetGenerator与resetTypist两个方法,以resetGenerator方法为例,将generator变量变成AtomicRerence相同引发上面描写叙述的问题。




    通知与Atomic变量

    import java.awt.*;
    import javax.swing.*;
    import java.util.concurrent.*;
    import java.util.concurrent.atomic.*;
    import javathreads.examples.ch05.*;
    
    public class AnimatedCharacterDisplayCanvas extends CharacterDisplayCanvas implements CharacterListener, Runnable {
    
        private AtomicBoolean done = new AtomicBoolean(true);
        private AtomicInteger curX = new AtomicInteger(0);
        private AtomicInteger tempChar = new AtomicInteger(0);
        private Thread timer = null;
    
        public AnimatedCharacterDisplayCanvas() {
            startAnimationThread();
        }
    
        public AnimatedCharacterDisplayCanvas(CharacterSource cs) {
            super(cs);
            startAnimationThread();
        }
    
        private void startAnimationThread() {
            if (timer == null) {
                timer = new Thread(this);
                timer.start();
            }
        }
    
        public void newCharacter(CharacterEvent ce) {
            curX.set(0);
            tempChar.set(ce.character);
            repaint();
        }
    
        protected void paintComponent(Graphics gc) {
            char[] localTmpChar = new char[1];
            localTmpChar[0] = (char) tempChar.get();
            int localCurX = curX.get();
    
            Dimension d = getSize();
            int charWidth = fm.charWidth(localTmpChar[0]);
            gc.clearRect(0, 0, d.width, d.height);
            if (localTmpChar[0] == 0)
    
  • 相关阅读:
    C#-WebForm-★★★JQuery-动画★★★
    C#-WebForm-★★★JQuery知识——DOM操作★★★
    C#-WebForm-★★★JQuery知识——基础知识、选择器、事件★★★
    C#-WebForm-组合查询(Queryable延迟查询、Intersect交集)、分页展示基础
    C#-WebForm-★★★LinQ-数据的条件组合查询并进行分页展示(未加各种限定)★★★
    C#-WebForm-光棒效果
    C#-WebForm-LinQ-条件精确查询、高级查询
    C#-WebForm-LinQ(一)-LinQ:语言集成查询(Language Integrated Query)-增删改查、属性扩展
    C#-WebForm JS定时器
    ★★★正则表达式★★★
  • 原文地址:https://www.cnblogs.com/lytwajue/p/6817096.html
Copyright © 2011-2022 走看看