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传入的参数是一个不可变的地址,比如类的字节码
synchronized关键字的用法的更多相关文章
- java中synchronized关键字的用法
在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看这个关键字的用法. 因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识. j ...
- Java关键字-----------------java中synchronized关键字的用法
在java编程中,经常需要用到同步,而用得最多的也许是synchronized关键字了,下面看看这个关键字的用法. 因为synchronized关键字涉及到锁的概念,所以先来了解一些相关的锁知识. j ...
- Java基础-synchronized关键字的用法(转载)
synchronized--同步 顾名思义是用于同步互斥的作用的. 这里精简的记一下它的使用方法以及意义: 当synchronized修饰 this或者非静态方法或者是一个实例的时候,所同步的锁是加在 ...
- synchronized关键字的用法总结
synchronized关键字主要有以下这3种用法: 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁 修饰代 ...
- java多线程中synchronized关键字的用法
转自:http://www.cdtarena.com/javapx/201308/9596.html 由于同一进程内的多个线程共享内存空间,在Java中,就是共享实例,当多个线程试图同时修改某个实例的 ...
- 多线程,线程同步,synchronized关键字的用法
一.什么是多线程 Java多线程实现方式主要有四种:继承Thread类.实现Runnable接口.实现Callable接口通过FutureTask包装器来创建Thread线程.使用ExecutorSe ...
- Java:多线程,线程同步,synchronized关键字的用法(同步代码块、非静态同步方法、静态同步方法)
关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨synchronized关键字. sy ...
- synchronized 关键字的用法?
synchronized 关键字可以将对象或者方法标记为同步,以实现对对象和方法的互 斥访问,可以用 synchronized(对象) { - }定义同步代码块,或者在声明方法时 将 synchron ...
- Java synchronized关键字用法(清晰易懂)
本篇随笔主要介绍 java 中 synchronized 关键字常用法,主要有以下四个方面: 1.实例方法同步 2.静态方法同步 3.实例方法中同步块 4.静态方法中同步块 我觉得在学习synchro ...
随机推荐
- 几句话弄清楚Java参数传值还是传引用
最近刷题做了一些算法题,对于在递归函数调用的时候什么时候传入值,什么时候传入引用有疑问,在网上搜索了一下,得出了一下三条总结: 1.对象就是传引用 2.原始类型就是传值 3.String,Intege ...
- UIView的一些常用属性和方法
UIView的一些常用属性和方法 1. UIView的属性 UIView继承自UIResponder,拥有touches方法. - (instancetype)initWithFrame:(CGRec ...
- Nvidia CUDA 6 Installed In Ubuntu 12.04
环境:ubuntu 12.04 (x64) 如果不能够 service lightdm stop,显示:unknown service 或者其他的 sudo /etc/init.d/lightdm r ...
- WebBrowser中取对应的图片资源
在客户端中使用webbrower控件,控件中已显示网页,对应的图片资源应已下载完,下面从缓存中找到图片资源,两种方法都可 1.GetUrlCacheEntryInfo http://msdn.micr ...
- ImageView一例
参考自<疯狂android讲义>2.4节 效果如下: 当点击图上某点时,将之附近放大至下图. 布局文件: <LinearLayout xmlns:android="http ...
- 段的创建表user_segments
1.段的定义及类型 Oracle中的段(segment)是占用磁盘空间的一个对象,最常见的段类型包括: l 聚簇cluster l 表table l 表分区 tablepartition l ...
- [Head First Python]2. BIF(内置函数)
1- range() >>> for each in range(2): print(each) ... 0 1
- 提高MySQL数据库查询效率的几个技巧(转载)
[size=5][color=Red]提高MySQL数据库查询效率的几个技巧(转)[/color][/size] MySQL由于它本身的小巧和操作的高效, 在数据库应用中越来越多的被采用.我 ...
- 【iOS开发】collectionView 瀑布流实现
一.效果展示 二.思路分析 1> 布局的基本流程 当设置好collectionView的布局方式之后(UICollectionViewFlowLayout),当系统开始布局的时候,会调用 pre ...
- 利用raspberry pi搭建typecho笔记(三) typecho nginx sqlite FAQ
前言 这是一个汇总文,用来总结我在整个配置过程中遇到的各种问题.因为我在解决这些问题的过程中发现,typecho被部署在这种需要完全自己配置的平台上的情况是比较少的,相关的资料也比较少,所以我的解决过 ...