zoukankan      html  css  js  c++  java
  • synchronized关键字的用法

    synchronized用于给方法或者块加锁用的,只有获得该对象或者块的锁的对象才能够执行里面的代码,否则将阻塞在那里,等待该锁被释放,然后获得该锁继续执行。比如下面模拟售票的代码:

    /**
     * 模拟售车票
     *
     * @author Administrator
     *
     */
    public class SynchronizedDemo {

        public static void main(String[] args) {
            Runnable runnable = new Runnable() {
                int count = 10;
                public void run() {
                    while (true) {
                        if (count <= 0) {
                            break;
                        } else {
                                count--; //标记1
                                System.out.println(Thread.currentThread().getName()
                                        + ":还剩余" + count + "张车票");
                            try {
                                Thread.sleep(500);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            };
            Thread t1 = new Thread(runnable);
            Thread t2 = new Thread(runnable);
            t1.start();
            t2.start();
        }
    }
    运行结果:

    Thread-0:还剩余9张车票
    Thread-1:还剩余8张车票
    Thread-1:还剩余6张车票
    Thread-0:还剩余6张车票
    Thread-0:还剩余4张车票
    Thread-1:还剩余4张车票
    Thread-1:还剩余3张车票
    Thread-0:还剩余3张车票
    Thread-1:还剩余2张车票
    Thread-0:还剩余1张车票
    Thread-0:还剩余0张车票

    假如当前count=8,当t1运行完标记1(代码中红色的标记)的时候count=7,恰巧该线程的时间片用完了。这时候t2开始运行,当t2运行完标记1的时候count=6,接着输出count的值,会输出还剩余6张,此时t2的时间片用完后,t1开始接着标记1后面执行,输出count的值,会输出还剩余6张,这才输出了上述中的结果。

     

    解决办法:

    如果加入了synchronized代码块的话即可解决上述问题,核心代码如下

    synchronized (this) {//标记2
                                count--;
                                System.out.println(Thread.currentThread().getName() + ":还剩余" + count + "张车票");

    }

    其中this表示的是要锁住对象的地址。

    运行结果:

    Thread-0:还剩余9张车票
    Thread-1:还剩余8张车票
    Thread-0:还剩余7张车票
    Thread-1:还剩余6张车票
    Thread-1:还剩余5张车票
    Thread-0:还剩余4张车票
    Thread-1:还剩余3张车票
    Thread-0:还剩余2张车票
    Thread-0:还剩余1张车票
    Thread-1:还剩余0张车票

    这才是正确的结果,这是由于当t1要执行标记2(代码中红色已标明)的时候,首先会判断该地址是否被锁住,如果没有被锁住,就会执行coount--,而此时t1的时间片用完了,t2开始执行,当t2执行到标记2的时候,首先判断该地址是否被锁住,发现该地址已经被锁住了,于是t2等待锁的释放,当t2的时间片用完时,t1开始继续执行,此时接着上次执行的位置执行,输出count的值,然后释放锁,此时当t1的时间片用完后,t2发现该地址的锁被释放了,于是t2拿到该锁,然后进去执行。。。以此类推。将会正确输出结果。

     

    只有该this所指向的地址相同时synchronized代码块才会起到作用,比如,将count的类型改为Integer,synchronized代码块传入count的地址,核心代码如下:

    Integer count = 10;

    synchronized (count) {
                                count--; //标记3
                                System.out.println(Thread.currentThread().getName()
                                        + ":还剩余" + count + "张车票");
     }

    结果输出:

    Thread-1:还剩余8张车票
    Thread-0:还剩余9张车票
    Thread-1:还剩余6张车票
    Thread-0:还剩余6张车票
    Thread-0:还剩余5张车票
    Thread-1:还剩余4张车票
    Thread-0:还剩余2张车票
    Thread-1:还剩余2张车票
    Thread-0:还剩余1张车票
    Thread-1:还剩余0张车票

    结果解析:

    假如现在count=4,t1将count的地址锁住后,执行完标记3后count=3,假设此时t1时间片用完,而此时t2开始执行,t2首先判断count的地址是否被锁住,发现此时count的地址并没有被锁住,这是因为t1锁住的是count=4的地址,而此时t2判断的是count=3的地址是否被锁住,而count=3的地址并没有被锁住,所以t2会执行代码块中的代码,执行完标记3后count=2,然后输出还剩余2张车票,当t2的时间片用完后,t1开始继续执行输出还剩余2张车票,所以出现上述的现象。就是因为count的地址是变化的,所以一般给synchronized传入的参数是一个不可变的地址,比如类的字节码

  • 相关阅读:
    linux 制作不用密碼可立即登入的 ssh 用戶
    大部分人都会忽略的Python易错点总结
    Python:有参装饰器与多个装饰器装饰一个函数
    Python面向对象中super用法与MRO机制
    Python实现一个键对应多个值的字典(multidict)
    python中*和**的打包和解包
    面试题:python 中 staticmethod 和 classmethod有什么区别
    Python小练习:StringIO和BytesIO读写操作的小思考
    Python中为什么不能用可变对象作为默认参数的值
    django中csrftoken跨站请求伪造的几种方式
  • 原文地址:https://www.cnblogs.com/biao2015/p/4493233.html
Copyright © 2011-2022 走看看