原力计划关于JAVA 中volatile使用的一些笔记

写在前面

我的需求:

  • CSDN 看到一个小伙伴问了这样JAVA并发的问题,然后我做了解答,主要使用了 volatile

(1)某电影放映厅一共有10排,每排10个座位,座位号为“排号+列号”,如第8排,座位号是8A-8J;

(2)此放映厅某一场次现有100张票要卖出,观众可以通过四个渠道购票:电影院、时光网、美团和支付宝;

(3)各个售票点的效率不同,每卖出一张票,各个售票点所需要的时间分别为:电影院3秒,时光网5秒,美团2秒,支付宝6秒;

现在这4个售票点同时售票,根据以上信息,用多线程模拟这4个售票点的售票情况。要求打印出每个售票点所卖出电影票的座位号,座位号随机确定。

我需要解决的问题:

  • 答完之后他反馈有问题,我测了几次,发现确实有问题。会有打印重票的时候,对于 volatile 的理解有些问题

我是这样做的:

  • 微信群里问了大佬。使用了原子类(atomic)解决这个问题。
  • 这里对volatile总结一下,当然没有涉及啥底层的东西,很浅。

太敏感的人会体谅到他人的痛苦,自然就无法轻易做到坦率。所谓的坦率,其实就是暴力。-----太宰治《候鸟》

我们先来看看他这到题,座位号随机确定我们直接用数子自增模拟,没有实现,想实现的话,可以把所有的号码随机初始化一个Set,然后每次pull一个出来。

下面是我最开始的解决方案,使用 volatile 来处理线程安全问题,认为我每次都可以拿到最新的,即可以满足线程安全。但是打印出来的数据有重复的,忽略了volatile修饰变量不满足原子性的问题,而 index++ 本身也不是原子操作,所以会有重票的问题

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#333333"><strong>import</strong></span> java.util.ArrayList;
<span style="color:#333333"><strong>import</strong></span> java.util.HashMap;
<span style="color:#333333"><strong>import</strong></span> java.util.Map;
<span style="color:#333333"><strong>import</strong></span> java.util.concurrent.TimeUnit;


<span style="color:#888888">/**
 * <span style="color:#333333"><strong>@Classname</strong></span> Ticket
 * <span style="color:#333333"><strong>@Description</strong></span> TODO
 * <span style="color:#333333"><strong>@Date</strong></span> 2021/12/8 19:00
 * <span style="color:#333333"><strong>@Created</strong></span> LiRuilong
 */</span>
<span style="color:#333333"><strong>public</strong></span> <span style="color:#333333"><strong>class</strong></span> <span style="color:#880000"><strong>Ticket</strong></span> <span style="color:#333333"><strong>implements</strong></span> <span style="color:#880000"><strong>Runnable</strong></span> {
 
    <span style="color:#888888">//最多受理100笔业务</span>
    <span style="color:#333333"><strong>private</strong></span> <span style="color:#333333"><strong>static</strong></span> <span style="color:#333333"><strong>final</strong></span> <span style="color:#333333"><strong>int</strong></span> MAX = <span style="color:#880000">100</span>;
    <span style="color:#888888">// 开始业务</span>
    <span style="color:#888888">//static AtomicInteger index = new AtomicInteger(0);</span>
    <span style="color:#333333"><strong>private</strong></span> <span style="color:#333333"><strong>static</strong></span>   <span style="color:#333333"><strong>volatile</strong></span> <span style="color:#333333"><strong>int</strong></span> index = <span style="color:#880000">0</span>;
    <span style="color:#888888">// 电影院3秒,时光网5秒,美团2秒,支付宝6秒;</span>
    <span style="color:#333333"><strong>private</strong></span> <span style="color:#333333"><strong>static</strong></span> <span style="color:#333333"><strong>volatile</strong></span> Map<String, ArrayList> map = <span style="color:#333333"><strong>new</strong></span> HashMap() {
 {
 
        put(<span style="color:#880000">"电影院"</span>, <span style="color:#333333"><strong>new</strong></span> ArrayList<>());
        put(<span style="color:#880000">"时光网"</span>, <span style="color:#333333"><strong>new</strong></span> ArrayList<>());
        put(<span style="color:#880000">"美团"</span>, <span style="color:#333333"><strong>new</strong></span> ArrayList<>());
        put(<span style="color:#880000">"支付宝"</span>, <span style="color:#333333"><strong>new</strong></span> ArrayList<>());
    }};

    <span style="color:#1f7199">@Override</span>
    <span style="color:#333333"><strong>public</strong></span> <span style="color:#333333"><strong>void</strong></span> <span style="color:#880000"><strong>run</strong></span>() {
 
        <span style="color:#333333"><strong>while</strong></span> (index < MAX) {
 
            <span style="color:#333333"><strong>try</strong></span> {
 
                String currentThreadName = Thread.currentThread().getName();
                <span style="color:#333333"><strong>switch</strong></span> (currentThreadName) {
 
                    <span style="color:#333333"><strong>case</strong></span> <span style="color:#880000">"电影院"</span>: {
 
                        map.get(<span style="color:#880000">"电影院"</span>).add(++index);
                        TimeUnit.MILLISECONDS.sleep(<span style="color:#880000">3</span>);
                    }
                    <span style="color:#333333"><strong>break</strong></span>;
                    <span style="color:#333333"><strong>case</strong></span> <span style="color:#880000">"时光网"</span>: {
 
                        map.get(<span style="color:#880000">"时光网"</span>).add(++index);
                        TimeUnit.MILLISECONDS.sleep(<span style="color:#880000">5</span>);
                    }
                    <span style="color:#333333"><strong>break</strong></span>;
                    <span style="color:#333333"><strong>case</strong></span> <span style="color:#880000">"美团"</span>: {
 
                        map.get(<span style="color:#880000">"美团"</span>).add(++index);
                        TimeUnit.MILLISECONDS.sleep(<span style="color:#880000">2</span>);
                    }
                    <span style="color:#333333"><strong>break</strong></span>;
                    <span style="color:#333333"><strong>case</strong></span> <span style="color:#880000">"支付宝"</span>: {
 
                        map.get(<span style="color:#880000">"支付宝"</span>).add(++index);
                        TimeUnit.MILLISECONDS.sleep(<span style="color:#880000">6</span>);
                    }
                    <span style="color:#333333"><strong>break</strong></span>;
                    <span style="color:#333333"><strong>default</strong></span>:
                        <span style="color:#333333"><strong>break</strong></span>;
                }
            } <span style="color:#333333"><strong>catch</strong></span> (Exception e) {
 
                e.printStackTrace();
            }
        }
    }

    <span style="color:#333333"><strong>public</strong></span> <span style="color:#333333"><strong>static</strong></span> <span style="color:#333333"><strong>void</strong></span> <span style="color:#880000"><strong>main</strong></span>(String[] args) {
 

        <span style="color:#333333"><strong>final</strong></span> Ticket task = <span style="color:#333333"><strong>new</strong></span> Ticket();
        <span style="color:#888888">//电影院3秒,时光网5秒,美团2秒,支付宝6秒;</span>
        <span style="color:#333333"><strong>new</strong></span> Thread(task, <span style="color:#880000">"电影院"</span>).start();
        <span style="color:#333333"><strong>new</strong></span> Thread(task, <span style="color:#880000">"时光网"</span>).start();
        <span style="color:#333333"><strong>new</strong></span> Thread(task, <span style="color:#880000">"美团"</span>).start();
        <span style="color:#333333"><strong>new</strong></span> Thread(task, <span style="color:#880000">"支付宝"</span>).start();

        Runtime.getRuntime().addShutdownHook(<span style="color:#333333"><strong>new</strong></span> Thread() {
 
            <span style="color:#1f7199">@Override</span>
            <span style="color:#333333"><strong>public</strong></span> <span style="color:#333333"><strong>void</strong></span> <span style="color:#880000"><strong>run</strong></span>() {
 
                map.forEach((o1, o2) -> {
 
                    System.out.println(o1 + <span style="color:#880000">" | 总票数:"</span>+o2.size()+o2.stream().reduce(<span style="color:#880000">":"</span>, (a, b) -> a + <span style="color:#880000">" "</span> + b));
                });
            }
        });
    }
}

==========================
支付宝 | 总票数:<span style="color:#880000">18</span>: <span style="color:#880000">2</span> <span style="color:#880000">8</span> <span style="color:#880000">13</span> <span style="color:#880000">18</span> <span style="color:#880000">24</span> <span style="color:#880000">30</span> <span style="color:#880000">36</span> <span style="color:#880000">41</span> <span style="color:#880000">47</span> <span style="color:#880000">53</span> <span style="color:#880000">58</span> <span style="color:#880000">64</span> <span style="color:#880000">69</span> <span style="color:#880000">77</span> <span style="color:#880000">82</span> <span style="color:#880000">87</span> <span style="color:#880000">94</span> <span style="color:#880000">100</span>
电影院 | 总票数:<span style="color:#880000">32</span>: <span style="color:#880000">3</span> <span style="color:#880000">4</span> <span style="color:#880000">7</span> <span style="color:#880000">10</span> <span style="color:#880000">12</span> <span style="color:#880000">16</span> <span style="color:#880000">19</span> <span style="color:#880000">23</span> <span style="color:#880000">25</span> <span style="color:#880000">27</span> <span style="color:#880000">32</span> <span style="color:#880000">35</span> <span style="color:#880000">37</span> <span style="color:#880000">40</span> <span style="color:#880000">43</span> <span style="color:#880000">46</span> <span style="color:#880000">49</span> <span style="color:#880000">52</span> <span style="color:#880000">56</span> <span style="color:#880000">58</span> <span style="color:#880000">62</span> <span style="color:#880000">65</span> <span style="color:#880000">68</span> <span style="color:#880000">73</span> <span style="color:#880000">76</span> <span style="color:#880000">80</span> <span style="color:#880000">83</span> <span style="color:#880000">86</span> <span style="color:#880000">89</span> <span style="color:#880000">92</span> <span style="color:#880000">95</span> <span style="color:#880000">98</span>
时光网 | 总票数:<span style="color:#880000">20</span>: <span style="color:#880000">1</span> <span style="color:#880000">5</span> <span style="color:#880000">10</span> <span style="color:#880000">14</span> <span style="color:#880000">20</span> <span style="color:#880000">24</span> <span style="color:#880000">28</span> <span style="color:#880000">34</span> <span style="color:#880000">38</span> <span style="color:#880000">44</span> <span style="color:#880000">48</span> <span style="color:#880000">54</span> <span style="color:#880000">59</span> <span style="color:#880000">64</span> <span style="color:#880000">71</span> <span style="color:#880000">75</span> <span style="color:#880000">81</span> <span style="color:#880000">85</span> <span style="color:#880000">91</span> <span style="color:#880000">97</span>
美团 | 总票数:<span style="color:#880000">43</span>: <span style="color:#880000">2</span> <span style="color:#880000">4</span> <span style="color:#880000">6</span> <span style="color:#880000">9</span> <span style="color:#880000">11</span> <span style="color:#880000">12</span> <span style="color:#880000">15</span> <span style="color:#880000">17</span> <span style="color:#880000">21</span> <span style="color:#880000">22</span> <span style="color:#880000">24</span> <span style="color:#880000">26</span> <span style="color:#880000">29</span> <span style="color:#880000">31</span> <span style="color:#880000">33</span> <span style="color:#880000">36</span> <span style="color:#880000">37</span> <span style="color:#880000">39</span> <span style="color:#880000">42</span> <span style="color:#880000">45</span> <span style="color:#880000">47</span> <span style="color:#880000">50</span> <span style="color:#880000">51</span> <span style="color:#880000">55</span> <span style="color:#880000">57</span> <span style="color:#880000">60</span> <span style="color:#880000">61</span> <span style="color:#880000">63</span> <span style="color:#880000">66</span> <span style="color:#880000">67</span> <span style="color:#880000">70</span> <span style="color:#880000">72</span> <span style="color:#880000">74</span> <span style="color:#880000">78</span> <span style="color:#880000">79</span> <span style="color:#880000">82</span> <span style="color:#880000">84</span> <span style="color:#880000">86</span> <span style="color:#880000">88</span> <span style="color:#880000">90</span> <span style="color:#880000">93</span> <span style="color:#880000">96</span> <span style="color:#880000">99</span></span></span>

后来通过使用原子类,使用了AtomicInteger来满足index++的原子性,票数可以正常的打印出来。

<span style="color:#444444"><span style="background-color:#f6f6f6"><span style="color:#333333"><strong>package</strong></span> com.ztesoft.pwd.bo;

<span style="color:#333333"><strong>import</strong></span> java.util.ArrayList;
<span style="color:#333333"><strong>import</strong></span> java.util.HashMap;
<span style="color:#333333"><strong>import</strong></span> java.util.Map;
<span style="color:#333333"><strong>import</strong></span> java.util.concurrent.TimeUnit;
<span style="color:#333333"><strong>import</strong></span> java.util.concurrent.atomic.AtomicInteger;

<span style="color:#888888">/**
 * <span style="color:#333333"><strong>@Classname</strong></span> Ticket
 * <span style="color:#333333"><strong>@Description</strong></span> TODO
 * <span style="color:#333333"><strong>@Date</strong></span> 2021/12/8 19:00
 * <span style="color:#333333"><strong>@Created</strong></span> LiRuilong
 */</span>
<span style="color:#333333"><strong>public</strong></span> <span style="color:#333333"><strong>class</strong></span> <span style="color:#880000"><strong>Ticket</strong></span> <span style="color:#333333"><strong>implements</strong></span> <span style="color:#880000"><strong>Runnable</strong></span> {
 
    <span style="color:#888888">//最多受理100笔业务</span>
    <span style="color:#333333"><strong>private</strong></span> <span style="color:#333333"><strong>static</strong></span> <span style="color:#333333"><strong>final</strong></span> <span style="color:#333333"><strong>int</strong></span> MAX = <span style="color:#880000">100</span>;
    <span style="color:#888888">// 开始业务</span>
    <span style="color:#333333"><strong>static</strong></span> AtomicInteger index = <span style="color:#333333"><strong>new</strong></span> AtomicInteger(<span style="color:#880000">0</span>);
    <span style="color:#888888">//private static   volatile int index = 0;</span>
    <span style="color:#888888">// 电影院3秒,时光网5秒,美团2秒,支付宝6秒;</span>
    <span style="color:#333333"><strong>private</strong></span> <span style="color:#333333"><strong>static</strong></span> <span style="color:#333333"><strong>volatile</strong></span> Map<String, ArrayList> map = <span style="color:#333333"><strong>new</strong></span> HashMap() {
 {
 
        put(<span style="color:#880000">"电影院"</span>, <span style="color:#333333"><strong>new</strong></span> ArrayList<>());
        put(<span style="color:#880000">"时光网"</span>, <span style="color:#333333"><strong>new</strong></span> ArrayList<>());
        put(<span style="color:#880000">"美团"</span>, <span style="color:#333333"><strong>new</strong></span> ArrayList<>());
        put(<span style="color:#880000">"支付宝"</span>, <span style="color:#333333"><strong>new</strong></span> ArrayList<>());
    }};

    <span style="color:#1f7199">@Override</span>
    <span style="color:#333333"><strong>public</strong></span> <span style="color:#333333"><strong>void</strong></span> <span style="color:#880000"><strong>run</strong></span>() {
 
        <span style="color:#333333"><strong>while</strong></span> (index.get() < MAX) {
 
            <span style="color:#333333"><strong>try</strong></span> {
 
                String currentThreadName = Thread.currentThread().getName();
                <span style="color:#333333"><strong>switch</strong></span> (currentThreadName) {
 
                    <span style="color:#333333"><strong>case</strong></span> <span style="color:#880000">"电影院"</span>: {
 
                        map.get(<span style="color:#880000">"电影院"</span>).add(index.addAndGet(<span style="color:#880000">1</span>));
                        TimeUnit.MILLISECONDS.sleep(<span style="color:#880000">3</span>);
                    }
                    <span style="color:#333333"><strong>break</strong></span>;
                    <span style="color:#333333"><strong>case</strong></span> <span style="color:#880000">"时光网"</span>: {
 
                        map.get(<span style="color:#880000">"时光网"</span>).add(index.addAndGet(<span style="color:#880000">1</span>));
                        TimeUnit.MILLISECONDS.sleep(<span style="color:#880000">5</span>);
                    }
                    <span style="color:#333333"><strong>break</strong></span>;
                    <span style="color:#333333"><strong>case</strong></span> <span style="color:#880000">"美团"</span>: {
 
                        map.get(<span style="color:#880000">"美团"</span>).add(index.addAndGet(<span style="color:#880000">1</span>));
                        TimeUnit.MILLISECONDS.sleep(<span style="color:#880000">2</span>);
                    }
                    <span style="color:#333333"><strong>break</strong></span>;
                    <span style="color:#333333"><strong>case</strong></span> <span style="color:#880000">"支付宝"</span>: {
 
                        map.get(<span style="color:#880000">"支付宝"</span>).add(index.addAndGet(<span style="color:#880000">1</span>));
                        TimeUnit.MILLISECONDS.sleep(<span style="color:#880000">6</span>);
                    }
                    <span style="color:#333333"><strong>break</strong></span>;
                    <span style="color:#333333"><strong>default</strong></span>:
                        <span style="color:#333333"><strong>break</strong></span>;
                }
            } <span style="color:#333333"><strong>catch</strong></span> (Exception e) {
 
                e.printStackTrace();
            }
        }
    }

    <span style="color:#333333"><strong>public</strong></span> <span style="color:#333333"><strong>static</strong></span> <span style="color:#333333"><strong>void</strong></span> <span style="color:#880000"><strong>main</strong></span>(String[] args) {
 

        <span style="color:#333333"><strong>final</strong></span> Ticket task = <span style="color:#333333"><strong>new</strong></span> Ticket();
        <span style="color:#888888">//电影院3秒,时光网5秒,美团2秒,支付宝6秒;</span>
        <span style="color:#333333"><strong>new</strong></span> Thread(task, <span style="color:#880000">"电影院"</span>).start();
        <span style="color:#333333"><strong>new</strong></span> Thread(task, <span style="color:#880000">"时光网"</span>).start();
        <span style="color:#333333"><strong>new</strong></span> Thread(task, <span style="color:#880000">"美团"</span>).start();
        <span style="color:#333333"><strong>new</strong></span> Thread(task, <span style="color:#880000">"支付宝"</span>).start();

        Runtime.getRuntime().addShutdownHook(<span style="color:#333333"><strong>new</strong></span> Thread() {
 
            <span style="color:#1f7199">@Override</span>
            <span style="color:#333333"><strong>public</strong></span> <span style="color:#333333"><strong>void</strong></span> <span style="color:#880000"><strong>run</strong></span>() {
 
                map.forEach((o1, o2) -> {
 
                    System.out.println(o1 + <span style="color:#880000">" | 总票数:"</span>+o2.size()+o2.stream().reduce(<span style="color:#880000">":"</span>, (a, b) -> a + <span style="color:#880000">" "</span> + b));
                });
            }
        });
    }
}

=================================
支付宝 | 总票数:<span style="color:#880000">16</span>: <span style="color:#880000">4</span> <span style="color:#880000">10</span> <span style="color:#880000">16</span> <span style="color:#880000">22</span> <span style="color:#880000">29</span> <span style="color:#880000">36</span> <span style="color:#880000">41</span> <span style="color:#880000">47</span> <span style="color:#880000">55</span> <span style="color:#880000">61</span> <span style="color:#880000">68</span> <span style="color:#880000">73</span> <span style="color:#880000">80</span> <span style="color:#880000">87</span> <span style="color:#880000">93</span> <span style="color:#880000">99</span>
电影院 | 总票数:<span style="color:#880000">27</span>: <span style="color:#880000">2</span> <span style="color:#880000">6</span> <span style="color:#880000">9</span> <span style="color:#880000">13</span> <span style="color:#880000">17</span> <span style="color:#880000">21</span> <span style="color:#880000">24</span> <span style="color:#880000">27</span> <span style="color:#880000">32</span> <span style="color:#880000">34</span> <span style="color:#880000">39</span> <span style="color:#880000">42</span> <span style="color:#880000">46</span> <span style="color:#880000">49</span> <span style="color:#880000">52</span> <span style="color:#880000">57</span> <span style="color:#880000">59</span> <span style="color:#880000">64</span> <span style="color:#880000">67</span> <span style="color:#880000">71</span> <span style="color:#880000">75</span> <span style="color:#880000">77</span> <span style="color:#880000">82</span> <span style="color:#880000">86</span> <span style="color:#880000">90</span> <span style="color:#880000">92</span> <span style="color:#880000">97</span>
时光网 | 总票数:<span style="color:#880000">17</span>: <span style="color:#880000">3</span> <span style="color:#880000">8</span> <span style="color:#880000">14</span> <span style="color:#880000">19</span> <span style="color:#880000">26</span> <span style="color:#880000">30</span> <span style="color:#880000">37</span> <span style="color:#880000">44</span> <span style="color:#880000">48</span> <span style="color:#880000">54</span> <span style="color:#880000">60</span> <span style="color:#880000">65</span> <span style="color:#880000">72</span> <span style="color:#880000">78</span> <span style="color:#880000">84</span> <span style="color:#880000">89</span> <span style="color:#880000">96</span>
美团 | 总票数:<span style="color:#880000">40</span>: <span style="color:#880000">1</span> <span style="color:#880000">5</span> <span style="color:#880000">7</span> <span style="color:#880000">11</span> <span style="color:#880000">12</span> <span style="color:#880000">15</span> <span style="color:#880000">18</span> <span style="color:#880000">20</span> <span style="color:#880000">23</span> <span style="color:#880000">25</span> <span style="color:#880000">28</span> <span style="color:#880000">31</span> <span style="color:#880000">33</span> <span style="color:#880000">35</span> <span style="color:#880000">38</span> <span style="color:#880000">40</span> <span style="color:#880000">43</span> <span style="color:#880000">45</span> <span style="color:#880000">50</span> <span style="color:#880000">51</span> <span style="color:#880000">53</span> <span style="color:#880000">56</span> <span style="color:#880000">58</span> <span style="color:#880000">62</span> <span style="color:#880000">63</span> <span style="color:#880000">66</span> <span style="color:#880000">69</span> <span style="color:#880000">70</span> <span style="color:#880000">74</span> <span style="color:#880000">76</span> <span style="color:#880000">79</span> <span style="color:#880000">81</span> <span style="color:#880000">83</span> <span style="color:#880000">85</span> <span style="color:#880000">88</span> <span style="color:#880000">91</span> <span style="color:#880000">94</span> <span style="color:#880000">95</span> <span style="color:#880000">98</span> <span style="color:#880000">100</span></span></span>

关于 volatile 的使用

被volatile关键字修饰的实例变量或者类变量具备两层语义:

  • 保证了不同线程之间对共享变量的可见性,
  • 禁止对volatile变量进行重排序。

每个线程都运行在栈内存中,每个线程都有自己的工作内存(Working Memory),比如寄存器Register,高速缓存存储器Cache等,线程的计算一般是通过工作内存进行交互的,线程在初始化时从主内存中加载所需要的变量值到工作内存中,然后在线程运行时,如果读取内存,则直接从工作内存中读取,若是写入则先写入到工作内存中,之后在刷新到主内存中。

在多线程情况下,可能读到的不是最新的值,可以使用 synchronized 同步代码块,或使用 Lock 锁来解决该问题。 JAVA 可以使用 volatile 解决,在变量前加 volatile 关键字,可以保证 每个线程对本地变量的访问和修改都是直接与主内存交互的,而不是与本线程的工作内存交互 。

但是Volatile关键字并不能保证线程安全,换句话讲它只能保证当前线程需要该变量的值能够获得最新的值,而不能保证多个线程修改的安全性。

使用 volatile ,需要保证:

  • 对变量的写操作不依赖于当前值;
  • 该变量没有包含在具有其他变量的不变式中

关于 volatile 的一些基本概念

volatile关键字只能修饰类变量和实例变量,对于方法参数,局部变量已及实例常量,类常量都不能进行修饰。

原子性,有序性和可见性

并发编程的三个重要的特性

可见性有序性原子性
当一个线程对共享变量进行了修改,那么另一个变量可以立即看到。 volatile 具有保证可见性的语义Java在运行期会对代码进行优化,执行顺序未必就是编译顺序, volatile 具有保证有序性的语义。多个原子性的操作在一起就不再是原子性操作了。
Java提供了以下三种方式来保证可见性Java提供了三种保证有序性的方式,具体如下简单的读取与赋值操作是原子性的,将一个变量赋给另外一个变量的操作不是原子性的。

使用关键字volatile,当一个变量被volatile关键字修饰时,对于共享资源的读操作会直接在主内存中进行(当然也会缓存到工作内存中,当其他线程对该共享资源进行了修改,则会导致当前线程在工作内存中的共享资源失效,所以必须从主内存中再次获取),对于共享资源的写操作当然是先要修改工作内存,但是修改结束后会立刻将其刷新到主内存中。

通synchronized 关键字实现,同步块保证任何时候只有一个线程获得锁,然后执行同步方法,并且还会确保在锁释放之前,会将对变量的修改刷新到主内存当中

通过JUC提供的显式锁Lock也能够保证可见性, Lock的lock方法能够保证在同一时刻只有一个线程获得锁然后执行同步方法,并且会确保在锁释放(Lock的unlock方法)之前会将对变量的修改刷新到主内存当中。

使用 volatile 关键字来保证有序性。使用 synchronized 关键字来保证有序性。使用 显式锁Lock 来保证有序性。Java内存模型(JMM)只保证了基本读取和赋值的原子性操作,其他的均不保证,如果想要使得某些代码片段具备原子性,需要使用关键字 synchronized ,或者 JUC 中的 lock 。如果想要使得int等类型自增操作具备原子性,可以使用 JUC包 下的原子封装类型 java.util.concurrent.atomic.*

volatile和synchronized区别

区别描述
使用上区别volatile关键字只能用来修饰实例变量或者类变量,不能修饰方法已及方法参数和局部变量和常量。
synchronized关键字不能用来修饰变量,只能用于修饰方法和语句块。
volatile修饰的变量可以为空,同步块的monitor不能为空。
对原子性的保证volatile无法保证原子性
synchronizde能够保证。因为无法被中途打断。
对可见性的保证都可以实现共享资源的可见性,但是实现的机制不同
synchronized借助于JVM指令monitor enter 和monitor exit ,通过排他的机制使线程串行通过同步块,在monitor退出后所共享的内存会被刷新到主内存中。
volatile使用机器指令(硬编码)的方式, lock 迫使其他线程工作内存中的数据失效,不得不主内存继续加载。
对有序性的保证volatile关键字禁止JVM编译器已及处理器对其进行重排序,能够保证有序性。
synchronized保证顺序性是串行化的结果,但同步块里的语句是会发生指令从排。
其他volatile不会使线程陷入阻塞
synchronized会会使线程进入阻塞。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值