在java中Synchronized的用法
synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。
在进一步阐述之前,我们需要明确几点:
A.无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
B.每个对象只有一个锁(lock)与之相关联。
C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
接着来讨论synchronized用到不同地方对代码产生的影响:
假设P1、P2是同一个类的不同对象,这个类中定义了以下几种情况的同步块或同步方法,P1、P2就都可以调用它们。
1. 把synchronized当作函数修饰符时,示例代码如下:
Public synchronized void methodAAA()
{
//….
}
这也就是同步方法,那这时synchronized锁定的是哪个对象呢?它锁定的是调用这个同步方法对象。也就是说,当一个对象P1在不同的线程中执行这个同步方法时,它们之间会形成互斥,达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却可以任意调用这个被加了synchronized关键字的方法。
上边的示例代码等同于如下代码:
public void methodAAA()
{
synchronized (this) // (1)
{
//…..
}
}
(1)处的this指的是什么呢?它指的就是调用这个方法的对象,如P1。可见同步方法实质是将synchronized作用于object reference。――那个拿到了P1对象锁的线程,才可以调用P1的同步方法,而对P2而言,P1这个锁与它毫不相干,程序也可能在这种情形下摆脱同步机制的控制,造成数据混乱。
2.同步块,示例代码如下:
public void method3(SomeObject so)
{
synchronized(so)
{
//…..
}
}
这时,锁就是so这个对象,谁拿到这个锁谁就可以运行它所控制的那段代码。当有一个明确的对象作为锁时,就可以这样写程序,但当没有明确的对象作为锁,只是想让一段代码同步时,可以创建一个特殊的instance变量(它得是一个对象)来充当锁:
class Foo implements Runnable
{
private byte[] lock = new byte[0]; // 特殊的instance变量
Public void methodA()
{
synchronized(lock) { //… }
}
//…..
}
注:零长度的byte数组对象创建起来将比任何对象都经济――查看编译后的字节码:生成零长度的byte[]对象只需3条操作码,而Object lock = new Object()则需要7行操作码。
3.将synchronized作用于static 函数,示例代码如下:
Class Foo
{
public synchronized static void methodAAA() // 同步的static 函数
{
//….
}
public void methodBBB()
{
synchronized(s) // class literal(类名称字面常量)
}
}
代码中的methodBBB()方法是把class literal作为锁的情况,它和同步的static函数产生的效果是一样的,取得的锁很特别,是当前调用这个方法的对象所属的类(Class,而不再是由这个Class产生的某个具体对象了)。
记得在《Effective Java》一书中看到过将 s和 lass()用于作同步锁还不一样,不能用lass()来达到锁这个Class的目的。P1指的是由Foo类产生的对象。
可以推断:如果一个类中定义了一个synchronized的static函数A,也定义了一个synchronized 的instance函数B,那么这个类的同一对象Obj在多线程中分别访问A和B两个方法时,不会构成同步,因为它们的锁都不一样。A方法的锁是Obj这个对象,而B的锁是Obj所属的.那个Class。
小结如下:
搞清楚synchronized锁定的是哪个对象,就能帮助我们设计更安全的多线程程序。
还有一些技巧可以让我们对共享资源的同步访问更加安全:
1. 定义private 的instance变量+它的 get方法,而不要定义public/protected的instance变量。如果将变量定义为public,对象在外界可以绕过同步方法的控制而直接取得它,并改动它。这也是JavaBean的标准实现方式之一。
2.如果instance变量是一个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。这个时候就需要将get方法也加上synchronized同步,并且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。
如果不再需要某个类,则该类在堆中所占用的空间通常将用于创建新对象。但是,如果应用程序通过创建类的新实例来处理请求,并且该应用程序的请求是随机出现的,则可能会发生以下情况:先前请求者完成后,正常的类垃圾回收将通过释放这个类占用的堆空间来清除这个类,但当下一个请求出现时,又必须将这个类重新实例化。在这种情况下,您可能想使用此选项来禁用类垃圾回收。
缺省值:
启用类垃圾回收
建议值:
禁用类垃圾回收
用法:
Xnoclassgc 禁用类垃圾回收
有关其他信息,请参阅下列 DeveloperWorks 文章:
调整 Sun JVM 的垃圾回收器
在 Solaris 平台上,WebSphere Application Server 在 Sun Hotspot JVM 上运行,而不是在 IBM JVM 上运行。对 Sun JVM 使用正确的调整参数以利用其性能优化功能十分重要。
Sun Hotspot JVM 依靠分代垃圾回收来实现最佳性能。下列命令行参数对于调整垃圾回收来说非常有用。
-XX:SurvivorRatio
将 Java 堆划分为旧对象(长生命周期对象)区域和新对象区域。新对象区域进一步细分为两部分,第一部分用于分配给新对象(初始区域),第二部分存放那些经过其前几次垃圾回收之后、但在被提升为旧对象之前仍在使用中的新对象(幸存者空间)。幸存者比率是堆的新对象区域中初始区域与幸存者空间的比率。增大此设置将针对需要创建大量对象但仅保留少量对象的应用程序优化 JVM。与其他应用程序相比,WebSphere Application Server 会生成更多中等生命周期对象和长生命周期对象,因此,应该将此设置设置为小于缺省值。
缺省值:
32
建议值:
16
用法:
-XX:SurvivorRatio=16
-XX:PermSize
为永久生成对象保留的堆区域存储 JVM 的所有反射数据。对于动态地装入和卸载大量类的应用程序来说,应该增大此大小以优化它们的性能。通过将此参数设置为 128MB,可以消除增大此部分堆所需的开销。
建议值:
128 MB
用法:
XX:PermSize=128m 将 perm 大小设置为 128 兆字节。
-Xmn
此设置控制允许新生成的对象在堆中耗用的空间量。正确调整此参数有助于降低垃圾回收开销,从而缩短服务器响应时间并提高吞吐量。此参数的缺省设置通常过低,这将导致执行大量的小型垃圾回收操作。如果将此参数设置得过高,可能会导致 JVM 仅执行大型(全面)垃圾回收。这些垃圾回收操作通常会耗时几秒钟,这将严重影响服务器的整体性能。您必须保持将此参数设置为小于整个堆大小的一半,以避免这种情况出现。
缺省值:
2228224 字节
建议值:
大约整个堆大小的 1/4
用法:
-Xmn256m 将大小设置为 256 兆字节。
-Xnoclassgc
缺省情况下,当一个类没有任何活动实例时,JVM 就会从内存中卸载该类,但是这样会使性能下降。如果关闭类垃圾回收,就可以消除由于多次装入和卸载同一个类而造成的开销。
如果不再需要某个类,则该类在堆中所占用的空间通常将用于创建新对象。但是,如果应用程序通过创建类的新实例来处理请求,并且该应用程序的请求是随机出现的,则可能会发生以下情况:先前请求者完成后,正常的类垃圾回收将通过释放这个类占用的堆空间来清除这个类,但当下一个请求出现时,又必须将这个类重新实例化。在这种情况下,您可能想使用此选项来禁用类垃圾回收。
缺省值:
启用类垃圾回收
建议值:
禁用类垃圾回收
用法:
Xnoclassgc 禁用类垃圾回收
有关调整 Sun JVM 的其他信息,请参阅 Java HotSpot VM 的性能文档。
调整 HP JVM 的垃圾回收器
HP JVM 依靠分代垃圾回收来实现最佳性能。下列命令行参数对于调整垃圾回收来说非常有用。
-Xoptgc
此设置针对包含许多短生命周期对象的应用程序优化 JVM。如果未指定此参数,则 JVM 通常执行大型(全面)垃圾回收。全面垃圾回收会花费几秒钟时间,这将显着影响服务器性能。
缺省值:
off
建议值:
on
用法:
-Xoptgc 启用优化的垃圾回收。
-XX:SurvivorRatio
将 Java 堆划分为旧对象(长生命周期对象)区域和新对象区域。新对象区域进一步细分为两部分,第一部分用于分配给新对象(初始区域),第二部分存放那些经过其前几次垃圾回收之后、但在被提升为旧对象之前仍在使用中的新对象(幸存者空间)。幸存者比率是堆的新对象区域中初始区域与幸存者空间的比率。增大此设置将针对需要创建大量对象但仅保留少量对象的应用程序优化 JVM。与其他应用程序相比,WebSphere Application Server 会生成更多中等生命周期对象和长生命周期对象,因此,应该将此设置设置为小于缺省值。
缺省值:
32
建议值:
16
用法:
-XX:SurvivorRatio=16
-XX:PermSize
为永久生成对象保留的堆区域存储 JVM 的所有反射数据。对于动态地装入和卸载大量类的应用程序来说,应该增大此大小以优化它们的性能。通过将此参数指定为 128 兆字节,可以消除增大此部分堆所需的开销。
缺省值:
0
建议值:
128 兆字节
用法:
-XX:PermSize=128m 将 PermSize 设置为 128 兆字节
-XX:+ForceMmapReserved
缺省情况下,Java 堆以“惰性交换”方式进行分配。在此方式下,将根据需要来分配内存页,这样可以节省交换空间,但是也将强制使用 4KB 页。在大型堆系统中,这种内存分配方式允许堆包含数以十万计的页。此命令禁用“惰性交换”并允许操作系统使用较大的内存页,从而优化对构成 Java 堆的内存的访问。
缺省值:
off
建议值:
on
用法:
-XX:+ForceMmapReserved 将禁用“惰性交换”。
-Xmn
此设置控制允许新生成的对象在堆中耗用的空间量。正确调整此参数有助于降低垃圾回收开销,从而缩短服务器响应时间并提高吞吐量。此参数的缺省设置通常过低,这将导致执行大量的小型垃圾回收操作。
缺省值:
没有缺省值
建议值:
大约整个堆大小的 3/4
用法:
-Xmn768m 将大小设置为 768 兆字节
虚拟页大小
通过将 Java 虚拟机的指令页大小和数据页大小设置为 64MB,可以提高性能。
缺省值:
4MB
建议值:
64MB
用法:
使用以下命令。命令输出提供了进程可执行文件的当前操作系统特征:
chatr +pi64M +pd64M /opt/WebSphere/
AppServer/java/bin/PA_RISC2.0/
native_threads/java -Xnoclassgc
缺省情况下,当一个类没有任何活动实例时,JVM 就会从内存中卸载该类,但是这样会使性能下降。如果关闭类垃圾回收,就可以消除由于多次装入和卸载同一个类而造成的开销。
如果不再需要某个类,则该类在堆中所占用的空间通常将用于创建新对象。但是,如果应用程序通过创建类的新实例来处理请求,并且该应用程序的请求是随机出现的,则可能会发生以下情况:先前请求者完成后,正常的类垃圾回收将通过释放这个类占用的堆空间来清除这个类,但当下一个请求出现时,又必须将这个类重新实例化。在这种情况下,您可能想使用此选项来禁用类垃圾回收。
缺省值:
启用类垃圾回收
建议值:
禁用类垃圾回收
用法:
Xnoclassgc 禁用类垃圾回收
有关调整 HP 虚拟机的其他信息,请参阅 Java 技术软件 HP-UX 11i。
调整 HP 的 JVM for HP-UX 设置下列选项以提高应用程序性能:
-XX:SchedulerPriorityRange=SCHED_NOAGE
ctorProvider=ollSelectorProvider
-XX:-ExtraPollBeforeRead
相關文章
-
Java中synchronized关键字的用法
synchronized关键字顾名思义,是用于同步互斥的作用的。这里精简的记一下它的使用方法以及意义:1. 当synchronized修饰 this或者非静态方法或者是一个实例的时候,所同步的锁是加在this或者实例对象引用上面的。比如a,b同 -
Java中synchronized的使用实例
synchronized关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、D等)正在用这个方法,若有则要等正在使用synchronized方法的线程B(或者C、D)运行完这个方法后再 -
Java 多线程之synchronized关键字详解
多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程可以进行操作,同步用以解决多个线程同时访问时可能出现的问题。 Java 多线程之synchronized关键字详解同步机制可以使用synchronized关键字实现。当syn -
Chinas Liu to seek injury advice in US soon英语作文
hinas world 110m hurdles champion liu iang works out at a training session in inzhuang, shanghai, september 24, .[osports]the 25-year-old athens gold medallist will consult medical eperts in three cit -
jQuery中的read和JavaScript中的onload函数的区别在哪
在JavaScript中,onload函数是最经常使用的,几乎涉及到JavaScript的童鞋都少不了要接触它。这个函数的作用就是等待网页完全装载完了以后再去执行代码块内的语句,因为按照文档流的执行顺序,通常用于头部加载JavaScript的` -
Should Private Cars Be Encouraged in China高中英语作文
with the rapid development of economy in china, the number of people who own private cars is rising day after day. quite different views eist as to this e is no doubt that private cars have been playi -
A Lifeguard at Johns Beach Saved a Drowning Child,A Lifeguar英语作文
在生活、工作和学习中,大家一定都接触过作文吧,作文是人们把记忆中所存储的有关知识、经验和思想用书面形式表达出来的记叙方式。为了让您在写作文时更加简单方便,下面是小编收集整理的'A Lifeguard at Johns Beach Sav -
JavaScript在Android的WebView中parseInt函数转换不正确
在银行实习,可以为你走向社会打下了坚实的基础。以下是本站小编整理的3篇银行金融单位实习鉴定,仅供参考,希望对大家有所帮助。银行金融单位实习鉴定篇一在刚刚过去的一个月中,我有幸来到中国工商银行绍兴县支行国际部和 -
Travels on Holidays in China 英语作文
Nowadays, more and more people like to travel in their holidays. The other day I read a report about the ways people spend their holidays. It is reported that in recent yiars several new holiday habit -
英语作文Travels On Holidaysin China
Nowadays, more and more people like to travel in their holidays. The other day I read a report about the ways people spend their holidays. It is reported that in recent yiars several new holiday habit