java同步和互斥
2023-09-14 09:06:43 时间
Java关键字synchronized是Java 语言提供的对多线程和同步的一种机制。synchronized可以作为函数的修饰符,也可作为函数内的语句。它可以作用于instance变量,对象引用(object reference),static函数和类名称字面常量(class literals)。
下面介绍一下synchronized的关键字的使用方法:
一、synchronized作函数修饰符
public
synchronized
void
fun()
{
……..
}
fun()就是一个同步方法,此时synchronized关键字锁定的是调用这个同步方法的对象。假设有p1和p2是同一个类的两个对象,p1在不同的线程中运行会对fun()产生互斥和同步的效果;但是p2对象和p1对象互相不会对fun()产生同步和互斥作用(当然,不同线程中的p2对象的fun()还是有同步和互斥)。
{
……..
}
对于非static的情况,synchronized是对象级别的,其实质是将synchronized作用于对象引用(object reference)上,即拿到p1对象锁的线程,对p1的fun()方法有同步互斥作用,不同的对象之间坚持“和平共处”。因此,上面的代码等同于:
public
void
fun()
{
synchronized( this ) // this指的是调用这个方法的对象
{
……
}
}
{
synchronized( this ) // this指的是调用这个方法的对象
{
……
}
}
二、synchronized同步程序块
public
void
fun_1(someObject obj)
{
synchronized (obj)
{
……
}
}
{
synchronized (obj)
{
……
}
}
上面代码中,锁住的是obj对象(正如前面说的,对于非static的情况,sysnchronized是对象级别的),谁拿到这个锁,谁就可运行obj控制的那段代码。通常情况,如果我们知道对用哪个对象作为锁时,就可以像上面的代码块一样使用synchronized。假如没有明确的对象作为锁,程序员又希望同步一段代码块,就可以使用下面的trick。
class
Test
implements
Runnable
{
private byte [] lock = new byte [ 0 ]; // 定一个instance变量
public void fun_2()
{
synchronized (lock)
{
……
}
}
}
{
private byte [] lock = new byte [ 0 ]; // 定一个instance变量
public void fun_2()
{
synchronized (lock)
{
……
}
}
}
在上面的代码示例中,定义了一个特殊的instance变量作为锁,这个instance变量必须是一个对象。定义lock为长度为0的数组对象是最佳方案。在编译后的字节码中,生成长度为0的byte[]只需要三条操作码。假如我们用所有类的超类Object来作锁,需要生成七条操作码。
[注意:]如果需要定义特殊的instance变量作为锁,最好将其定义为private的,同时定义其get()方法(如果使用自己定义的类的对象作为锁)。如果变量是public的,其他类的对象可以得到这个锁的控制权,并修改这个锁。这是非常不安全的。
[注意:] 如果instance变量是一个对象,如数组或ArrayList什么的,那上述方法仍然不安全,因为当外界对象通过get方法拿到这个instance对象的引用后,又将其指向另一个对象,那么这个private变量也就变了,岂不是很危险。这个时候就需要将get方法也加上synchronized同步,并且,只返回这个private对象的clone()――这样,调用端得到的就是对象副本的引用了。
三、synchronized修饰static方法
synchronized静态(static)方法的用法如下面代码示例:
public
static
synchronized
void
fun_3()
{
……
}
{
……
}
如果方法用static修饰,synchronized的作用范围就是class一级的,它对类的所有对象起作用。像第一点中的fun()方法,如果是static的,那么synchronized对p1对象和p2对象都起到同步互斥的作用。
其实说白了,对于static的synchronize也可以理解为对象级别的(hoho!是不是有点糊涂了? ^_^),因此下面代码可以达到同样效果:
class
XX
{
public static void fun_4()
{
synchronized (XX. class )
{
……
}
}
}
{
public static void fun_4()
{
synchronized (XX. class )
{
……
}
}
}
请注意,XX.class也是一个对象,类型是Class,在一个ClassLoader里,它是唯一的。因此,我在前面说,也理解它是对象级别的。
最后简单总结一下:
(1) 通常把synchronized关键字的作用范围划分为类的范围和对象的范围两种,不过偶个人理解的是,既然取得的锁都是对象(参考第三点),也可以认为synchronized关键字都作用于对象。
(2) synchronized关键字是不能继承的,即,父类的synchronized方法在子类中不是synchronized,必须要重新的显式的声明为synchronized才行。
(3) 实现同步需要很大的系统开销,导致延迟等待,甚至可能造成死锁,所以在非多线程情况下不要使用。
相关文章
- Java-GUI 编程之 JList、JComboBox实现列表框
- java 截位法保留小数_【数量关系速算技巧】泡泡截位法专题
- java 调用.asmx_Java调用asmx的一个例子
- java传真发送,用Java发送传真解决之道
- java使用md5_Java_MD5的使用「建议收藏」
- java oracle数据备份_Java实现Oracle数据库备份
- java jersey使用总结_jersey Java Jersey配置「建议收藏」
- Java内存模型是什么,为什么要有Java内存模型,Java内存模型解决了什么问题等。。。
- java json对象和json字符串互转的方法_java json转字符串
- java如何打印菱形_JAVA输出菱形
- Java岗大厂面试百日冲刺 - 日积月累,每日三题【Day02】——Java高级篇
- Jenkins + Docker 一键自动化部署 Java Spring Boot 应用最简流程
- 【愚公系列】2023年03月 Java教学课程 121-Maven的概念与基本使用
- 深入Linux环境下Java应用调试实践(linux调试java)
- 检查深入探索Redis与Java过期数据安全检查(redisjava过期)
- 处理使用Java与Redis实现过期键的管理(redisjava过期)
- 时间解决Redis中Java的过期时间问题(redisjava过期)
- 使用Redis优化Java开发的关键技巧(redis与java开发)
- Linux Java时区调整:让处理日期更加方便(linux java时区)
- Java程序在Linux系统中实现命令操作(java运行linux命令)
- Oracle收购了Java一个伟大的转折点(java被oracle吗)
- 收购Oracle收购Java重新定义软件开发未来(java被oracle)
- Java与Oracle同步一种新的数据库模式(java同步oracle)
- Java项目生成静态页面的代码
- java线程之线程的生命周期的使用