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传入的参数是一个不可变的地址,比如类的字节码

synchronized关键字的用法的更多相关文章

  1. java中synchronized关键字的用法

    在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看这个关键字的用法. 因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识. j ...

  2. Java关键字-----------------java中synchronized关键字的用法

    在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看这个关键字的用法. 因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识. j ...

  3. Java基础-synchronized关键字的用法(转载)

    synchronized--同步 顾名思义是用于同步互斥的作用的. 这里精简的记一下它的使用方法以及意义: 当synchronized修饰 this或者非静态方法或者是一个实例的时候,所同步的锁是加在 ...

  4. synchronized关键字的用法总结

    synchronized关键字主要有以下这3种用法: 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁 修饰代 ...

  5. java多线程中synchronized关键字的用法

    转自:http://www.cdtarena.com/javapx/201308/9596.html 由于同一进程内的多个线程共享内存空间,在Java中,就是共享实例,当多个线程试图同时修改某个实例的 ...

  6. 多线程,线程同步,synchronized关键字的用法

    一.什么是多线程 Java多线程实现方式主要有四种:继承Thread类.实现Runnable接口.实现Callable接口通过FutureTask包装器来创建Thread线程.使用ExecutorSe ...

  7. Java:多线程,线程同步,synchronized关键字的用法(同步代码块、非静态同步方法、静态同步方法)

    关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨synchronized关键字. sy ...

  8. synchronized 关键字的用法?

    synchronized 关键字可以将对象或者方法标记为同步,以实现对对象和方法的互 斥访问,可以用 synchronized(对象) { - }定义同步代码块,或者在声明方法时 将 synchron ...

  9. Java synchronized关键字用法(清晰易懂)

    本篇随笔主要介绍 java 中 synchronized 关键字常用法,主要有以下四个方面: 1.实例方法同步 2.静态方法同步 3.实例方法中同步块 4.静态方法中同步块 我觉得在学习synchro ...

随机推荐

  1. NFinal学习笔记 02—NFinalBuild

    在学习NFinal的过程中发现在线.net编译器Web版—— NFinalBuild 什么是NFinalBuild呢?它就是帮助我们简单又快速的更新我们网站的一种编译器,我们不用再只为了更新.net网 ...

  2. Windows下安装Django及WEB服务启动

           如果使用的是 Linux 或 Mac OS X ,系统可能已经预装了 Python .在命令提示符下 (或 OS X 的终端中) 输入python ,如果出现python编辑环境,说明 ...

  3. Ubuntu自定义命令

    回到主文件夹 $ cd ~ 建立.bash_aliases $ touch .bash_aliases $ vim .bash_aliases 在此文件中加入一句话: alias cdlauncher ...

  4. iOS开发~视图(UIView)与控件(UIControl)

    1.UIView类 1.什么是视图 看得见的都是视图 2.什么是控件 一种特殊的视图,都是UIControl的子类,不仅具有一定的显示外观,还能响应高级事件,与用户交互.严格意义上UILabel不是控 ...

  5. (原)Ubuntu16中安装cuda toolkit

    转载请注明出处: http://www.cnblogs.com/darkknightzh/p/5655957.html 参考网址: https://devtalk.nvidia.com/default ...

  6. 用GDAL/OGR去读shapefile

    一.读shapefile 1.首先,用Arcgis创建所要读的shp文件.打开ArcCatalog,右键NEW->Shapefile,名称Name:point ,要素类型(Feature Typ ...

  7. JSON 传值 textarea中虚拟换行功能

    遇到错误的袭击, 错误出现,使用jquery中ajax进行查询数据时执行完以后,需要把数据封装成为JSON类型的数据,并传递到前台去的时候出现Invalid JSON 错误,经查找后发现是在使用tex ...

  8. 关于Android Assets读取文件为File对象

    关于Android Assets读取文件为File对象的问题,在Assets里面放置文件,在使用的时候,一般是使用AssetManger对象,open方法获取InputStream 然后进行其他操作. ...

  9. PHP结合Linux的cron命令实现定时任务

    PHP死循环 来处理定时任务的效率是很低的.(众多网友评价)大家都建议使用Linux内置的定时任务crontab命令来调用php脚本来实现. PHP定时任务的两种方法:1.web方式调用php网页,但 ...

  10. 解决Webservice内存溢出-用XmlWriter

    XmlWriter 表示一个编写器,该编写器提供一种快速.非缓存和只进的方式来生成包含 XML 数据的流或文件.这个就可以不占用内存,将数据放入磁盘中.也就不会出现内存溢出 public class ...