synchronizedjava.docx
- 文档编号:25767072
- 上传时间:2023-06-13
- 格式:DOCX
- 页数:17
- 大小:21.53KB
synchronizedjava.docx
《synchronizedjava.docx》由会员分享,可在线阅读,更多相关《synchronizedjava.docx(17页珍藏版)》请在冰豆网上搜索。
synchronizedjava
Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。
另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。
也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。
结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
五、以上规则对其它对象锁同样适用.
举例说明:
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。
另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
packageths;
publicclassThread1implementsRunnable{
publicvoidrun(){
synchronized(this){
for(inti=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"synchronizedloop"+i);
}
}
}
publicstaticvoidmain(String[]args){
Thread1t1=newThread1();
Threadta=newThread(t1,"A");
Threadtb=newThread(t1,"B");
ta.start();
tb.start();
}
}
结果:
Asynchronizedloop0
Asynchronizedloop1
Asynchronizedloop2
Asynchronizedloop3
Asynchronizedloop4
Bsynchronizedloop0
Bsynchronizedloop1
Bsynchronizedloop2
Bsynchronizedloop3
Bsynchronizedloop4
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
packageths;
publicclassThread2{
publicvoidm4t1(){
synchronized(this){
inti=5;
while(i-->0){
System.out.println(Thread.currentThread().getName()+":
"+i);
try{
Thread.sleep(500);
}catch(InterruptedExceptionie){
}
}
}
}
publicvoidm4t2(){
inti=5;
while(i-->0){
System.out.println(Thread.currentThread().getName()+":
"+i);
try{
Thread.sleep(500);
}catch(InterruptedExceptionie){
}
}
}
publicstaticvoidmain(String[]args){
finalThread2myt2=newThread2();
Threadt1=newThread(newRunnable(){publicvoidrun(){myt2.m4t1();}},"t1");
Threadt2=newThread(newRunnable(){publicvoidrun(){myt2.m4t2();}},"t2");
t1.start();
t2.start();
}
}
结果:
t1:
4
t2:
4
t1:
3
t2:
3
t1:
2
t2:
2
t1:
1
t2:
1
t1:
0
t2:
0
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
//修改Thread2.m4t2()方法:
publicvoidm4t2(){
synchronized(this){
inti=5;
while(i-->0){
System.out.println(Thread.currentThread().getName()+":
"+i);
try{
Thread.sleep(500);
}catch(InterruptedExceptionie){
}
}
}
}
结果:
t1:
4
t1:
3
t1:
2
t1:
1
t1:
0
t2:
4
t2:
3
t2:
2
t2:
1
t2:
0
四、第三个例子同样适用其它同步代码块。
也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。
结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
//修改Thread2.m4t2()方法如下:
publicsynchronizedvoidm4t2(){
inti=5;
while(i-->0){
System.out.println(Thread.currentThread().getName()+":
"+i);
try{
Thread.sleep(500);
}catch(InterruptedExceptionie){
}
}
}
结果:
t1:
4
t1:
3
t1:
2
t1:
1
t1:
0
t2:
4
t2:
3
t2:
2
t2:
1
t2:
0
五、以上规则对其它对象锁同样适用:
packageths;
publicclassThread3{
classInner{
privatevoidm4t1(){
inti=5;
while(i-->0){
System.out.println(Thread.currentThread().getName()+":
Inner.m4t1()="+i);
try{
Thread.sleep(500);
}catch(InterruptedExceptionie){
}
}
}
privatevoidm4t2(){
inti=5;
while(i-->0){
System.out.println(Thread.currentThread().getName()+":
Inner.m4t2()="+i);
try{
Thread.sleep(500);
}catch(InterruptedExceptionie){
}
}
}
}
privatevoidm4t1(Innerinner){
synchronized(inner){//使用对象锁
inner.m4t1();
}
privatevoidm4t2(Innerinner){
inner.m4t2();
}
publicstaticvoidmain(String[]args){
finalThread3myt3=newThread3();
finalInnerinner=myt3.newInner();
Threadt1=newThread(newRunnable(){publicvoidrun(){myt3.m4t1(inner);}},"t1");
Threadt2=newThread(newRunnable(){publicvoidrun(){myt3.m4t2(inner);}},"t2");
t1.start();
t2.start();
}
}
结果:
尽管线程t1获得了对Inner的对象锁,但由于线程t2访问的是同一个Inner中的非同步部分。
所以两个线程互不干扰。
t1:
Inner.m4t1()=4
t2:
Inner.m4t2()=4
t1:
Inner.m4t1()=3
t2:
Inner.m4t2()=3
t1:
Inner.m4t1()=2
t2:
Inner.m4t2()=2
t1:
Inner.m4t1()=1
t2:
Inner.m4t2()=1
t1:
Inner.m4t1()=0
t2:
Inner.m4t2()=0
现在在Inner.m4t2()前面加上synchronized:
privatesynchronizedvoidm4t2(){
inti=5;
while(i-->0){
System.out.println(Thread.currentThread().getName()+":
Inner.m4t2()="+i);
try{
Thread.sleep(500);
}catch(InterruptedExceptionie){
}
}
}
结果:
尽管线程t1与t2访问了同一个Inner对象中两个毫不相关的部分,但因为t1先获得了对Inner的对象锁,所以t2对Inner.m4t2()的访问也被阻塞,因为m4t2()是Inner中的一个同步方法。
t1:
Inner.m4t1()=4
t1:
Inner.m4t1()=3
t1:
Inner.m4t1()=2
t1:
Inner.m4t1()=1
t1:
Inner.m4t1()=0
t2:
Inner.m4t2()=4
t2:
Inner.m4t2()=3
t2:
Inner.m4t2()=2
t2:
Inner.m4t2()=1
t2:
Inner.m4t2()=0
第二篇:
synchronized关键字,它包括两种用法:
synchronized方法和synchronized块。
1.synchronized方法:
通过在方法声明中加入synchronized关键字来声明synchronized方法。
如:
publicsynchronizedvoidaccessVal(intnewVal);
synchronized方法控制对类成员变量的访问:
每个类实例对应一把锁,每个synchronized方法都必须获得调用该方法的类实例的锁方能
执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行
状态。
这种机制确保了同一时刻对于每一个类实例,其所有声明为synchronized的成员函数中至多只有一个处于可执行状态(因为至多只有
一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为synchronized)
。
在Java中,不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员函数声明为synchronized,以控制其对类的静态成
员变量的访问。
synchronized方法的缺陷:
若将一个大的方法声明为synchronized将会大大影响效率,典型地,若将线程类的方法run()声明为
synchronized,由于在线程的整个生命期内它一直在运行,因此将导致它对本类任何synchronized方法的调用都永远不会成功。
当然我们可
以通过将访问类成员变量的代码放到专门的方法中,将其声明为synchronized,并在主方法中调用来解决这一问题,但是Java为我们提供
了更好的解决办法,那就是synchronized块。
2.synchronized块:
通过synchronized关键字来声明synchronized块。
语法如下:
synchronized(syncObject){
//允许访问控制的代码
}
synchronized块是这样一个代码块,其中的代码必须获得对象syncObject(如前所述,可以是类实例或类)的锁方能执行,具体机
制同前所述。
由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。
对synchronized(this)的一些理解
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。
另一个线
程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized
(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)
同步代码块的访问将被阻塞。
四、第三个例子同样适用其它同步代码块。
也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个
object的对象锁。
结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
五、以上规则对其它对象锁同样适用
java中synchronized用法
打个比方:
一个object就像一个大房子,大门永远打开。
房子里有很多房间(也就是方法)。
这些房间有上锁的(synchronized方法),和不上锁之分(普通方法)。
房门口放着一把钥匙(key),这把钥匙可以打开所有上锁的房间。
另外我把所有想调用该对象方法的线程比喻成想进入这房子某个房间的人。
所有的东西就这么多了,下面我们看看这些东西之间如何作用的。
在此我们先来明确一下我们的前提条件。
该对象至少有一个synchronized方法,否则这个key还有啥意义。
当然也就不会有我们的这个主题了。
一个人想进入某间上了锁的房间,他来到房子门口,看见钥匙在那儿(说明暂时还没有其他人要使用上锁的房间)。
于是他走上去拿到了钥匙
,并且按照自己的计划使用那些房间。
注意一点,他每次使用完一次上锁的房间后会马上把钥匙还回去。
即使他要连续使用两间上锁的房间,
中间他也要把钥匙还回去,再取回来。
因此,普通情况下钥匙的使用原则是:
“随用随借,用完即还。
”
这时其他人可以不受限制的使用那些不上锁的房间,一个人用一间可以,两个人用一间也可以,没限制。
但是如果当某个人想要进入上锁的房
间,他就要跑到大门口去看看了。
有钥匙当然拿了就走,没有的话,就只能等了。
要是很多人在等这把钥匙,等钥匙还回来以后,谁会优先得到钥匙?
Notguaranteed。
象前面例子里那个想连续使用两个上锁房间的家伙,他
中间还钥匙的时候如果还有其他人在等钥匙,那么没有任何保证这家伙能再次拿到。
(JAVA规范在很多地方都明确说明不保证,象
Thread.sleep()休息后多久会返回运行,相同优先权的线程那个首先被执行,当要访问对象的锁被释放后处于等待池的多个线程哪个会优先得
到,等等。
我想最终的决定权是在JVM,之所以不保证,就是因为JVM在做出上述决定的时候,绝不是简简单单根据一个条件来做出判断,而是
根据很多条。
而由于判断条件太多,如果说出来可能会影响JAVA的推广,也可能是因为知识产权保护的原因吧。
SUN给了个不保证就混过去了
。
无可厚非。
但我相信这些不确定,并非完全不确定。
因为计算机这东西本身就是按指令运行的。
即使看起来很随机的现象,其实都是有规律
可寻。
学过计算机的都知道,计算机里随机数的学名是伪随机数,是人运用一定的方法写出来的,看上去随机罢了。
另外,或许是因为要想弄
的确定太费事,也没多大意义,所以不确定就不确定了吧。
)
再来看看同步代码块。
和同步方法有小小的不同。
1.从尺寸上讲,同步代码块比同步方法小。
你可以把同步代码块看成是没上锁房间里的一块用带锁的屏风隔开的空间。
2.同步代码块还可以人为的指定获得某个其它对象的key。
就像是指定用哪一把钥匙才能开这个屏风的锁,你可以用本房的钥匙;你也可以指定
用另一个房子的钥匙才能开,这样的话,你要跑到另一栋房子那儿把那个钥匙拿来,并用那个房子的钥匙来打开这个房子的带锁的屏风。
记住你获得的那另一栋房子的钥匙,并不影响其他人进入那栋房子没有锁的房间。
为什么要使用同步代码块呢?
我想应该是这样的:
首先对程序来讲同步的部分很影响运行效率,而一个方法通常是先创建一些局部变
量,再对这些变量做一些操作,如运算,显示等等;而同步所覆盖的代码越多,对效率的影响就越严重。
因此我们通常尽量缩小其影响范围。
如何做?
同步代码块。
我们只把一个方法中该同步的地方同步,比如运算。
另外,同步代码块可以指定钥匙这一特点有个额外的好处,是可以在一定时期内霸占某个对象的key。
还记得前面说过普通情况下钥
匙的使用原则吗。
现在不是普通情况了。
你所取得的那把钥匙不是永远不还,而是在退出同步代码块时才还。
还用前面那个想连续用两个上锁房间的家伙打比方。
怎样才能在用完一间以后,继续使用另一间呢。
用同步代码块吧。
先创建另外
一个线程,做一个同步代码块,把那个代码块的锁指向这个房子的钥匙。
然后启动那个线程。
只要你能在进入那个代码块时抓到这房子的钥匙
,你就可以一直保留到退出那个代码块。
也就是说你甚至可以对本房内所有上锁的房间遍历,甚至再sleep(10*60*1000),而房门口却还有
1000个线程在等这把钥匙呢。
很过瘾吧。
在此对sleep()方法和钥匙的关联性讲一下。
一个线程在拿到key后,且没有完成同步的内容时,如果被强制sleep()了,那key还一
直在它那儿。
直到它再次运行,做完所有同步内容,才会归还key。
记住,那家伙只是干活干累了,去休息一下,他并没干完他要干的事。
为
了避免别人进入那个房间把里面搞的一团糟,即使在睡觉的时候他也要把那唯一的钥匙戴在身上。
最后,也许有人会问,为什么要一把钥匙通开,而不是一个钥匙一个门呢?
我想这纯粹是因为复杂性问题。
一个钥匙一个门当然更
安全,但是会牵扯好多问题。
钥匙的产生,保管,获得,归还等等。
其复杂性有可能随同步方法的增加呈几何级数增加,严重影响效率。
这也
算是一个权衡的问题吧。
为了增加一点点安全性,导致效率大大降低,是多么不可取啊。
synchronized的一个简单例子
publicclassTextThread{
publicstaticvoidmain(String[]args){
TxtThreadtt=newTxtThread();
newThread(tt).start();
newThread(tt).start();
newThread(tt).start();
newThread(tt).start();
}
}
classTxtThreadimplementsRunnable{
intnum=100;
Stringstr=newString();
publicvoidrun(){
synchronized(str){
while(num>0){
try{
Thread.sleep
(1);
}catch(Exceptione){
e.getMessage();
}
System.out.println(Thread.currentThread().getName()
+"thisis"+num--);
}
}
}
}
上面的例子中为了制造一个时间差,也就是出错的机会,使用了Thread.sleep(10)
Java对多线程的支持与同步机制深受大家的喜爱,似乎看起来使用了synchronized关键字就可以轻松地解决多线程共享数据同步问题。
到底如
何?
――还得对synchronized关键字的作用进行深入了解才可定论。
总的说来,synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。
如果再细的分类,
synchronized可作用于instance变量、objectreference(对象引用)、static函数和classliterals(类名称字面常量)身上。
在进一步阐述之前,我们需要明确几点:
A.无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其
他线程的对象访问。
B.每个对象只有一个锁(lock)与之相关联。
C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
接着来讨论synchronized用到不同地方对代码产生的影响:
假设P1、P2是同一个类的不同对象,这个类中定义了以下几种情况的同步块或同步方法,P1、P2就都可以调用它们。
1.把synchronized当作函数修饰符时,示例代码如下:
PublicsynchronizedvoidmethodAAA()
{
//….
}
这也就是同步方法,那这时synchronized锁定的是哪个对象呢?
它锁定的是调用这个同步方法对象。
也就是说,当一个对象P1在不同的线程中
执行这个同
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- synchronizedjava