synchronized(this)的意思是:

本文详细解释了Java中synchronized(this)关键字如何在并发线程间控制对象访问,包括一个线程对对象的同步代码块的独占访问,以及非同步代码块的并发访问。通过实例演示了同步代码块之间的互斥执行,以及同一对象不同同步代码块之间的访问控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


 

一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

五、以上规则对其它对象锁同样适用.

 

举例说明:

 

一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

package ths;

public class Thread1 implements Runnable {
public void run() {
synchronized(this) {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);
}
}
}
public static void main(String[] args) {
Thread1 t1 = new Thread1();
Thread ta = new Thread(t1, "A");
Thread tb = new Thread(t1, "B");
ta.start();
tb.start();
}
}

 

结果:

A synchronized loop 0
A synchronized loop 1
A synchronized loop 2
A synchronized loop 3
A synchronized loop 4

B synchronized loop 0
B synchronized loop 1
B synchronized loop 2
B synchronized loop 3
B synchronized loop 4

二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

package ths;

public class Thread2 {
public void m4t1() {
synchronized(this) {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
}
public void m4t2() {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}
public static void main(String[] args) {
final Thread2 myt2 = new Thread2();
Thread t1 = new Thread(
new Runnable() {
public void run() {
myt2.m4t1();
}
}, "t1"
);
Thread t2 = new Thread(
new Runnable() {
public void run() {
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()方法:

public void m4t2() {
synchronized(this) {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}

}

结果:

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()方法如下:

public synchronized void m4t2() {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
}
}

 

结果:

t1 : 4
t1 : 3
t1 : 2
t1 : 1
t1 : 0

t2 : 4
t2 : 3
t2 : 2
t2 : 1
t2 : 0

 

五、以上规则对其它对象锁同样适用:

package ths;

public class Thread3 {
class Inner {
private void m4t1() {
int i = 5;
while(i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : Inner.m4t1()=" + i);
try {
Thread.sleep(500);
} catch(InterruptedException ie) {
}
}
}
private void m4t2() {
int i = 5;
while(i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);
try {
Thread.sleep(500);
} catch(InterruptedException ie) {
}
}
}
}
private void m4t1(Inner inner) {
synchronized(inner) { //使用对象锁
inner.m4t1();
}
}
private void m4t2(Inner inner) {
inner.m4t2();
}
public static void main(String[] args) {
final Thread3 myt3 = new Thread3();
final Inner inner = myt3.new Inner();
Thread t1 = new Thread(
new Runnable() {
public void run() {
myt3.m4t1(inner);
}
}, "t1"
);
Thread t2 = new Thread(
new Runnable() {
public void run() {
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:

 

private synchronized void m4t2() {
int i = 5;
while(i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : Inner.m4t2()=" + i);
try {
Thread.sleep(500);
} catch(InterruptedException ie) {
}
}
}

 

结果:

尽管线程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

<think>好的,我现在需要帮助用户理解Java中synchronized修饰代码块时锁定的对象及其原理。首先,我要回忆一下synchronized的基本概念,然后结合用户提供的引用内容来组织答案。 用户的问题是关于synchronized代码块锁定对象的原理,我需要详细解释不同情况下锁定的对象是什么,以及背后的机制。根据引用内容,synchronized可以锁定实例对象、类对象,或者任意共享对象。例如,当使用synchronized(this)时,锁定的是当前实例对象;而锁定类的静态方法或类对象时,所有实例共享同一把锁。 接下来,我需要确保回答结构清晰,分点说明不同锁定方式,并举例说明。同时,要提到内置锁(监视器锁)的概念,以及锁的获取和释放机制。还要注意同步带来的性能影响和死锁问题,这部分引用中也有提到。 然后,生成相关问题。需要根据用户的问题,提出几个相关的问题,比如对象锁与类锁的区别、锁竞争的影响、与ReentrantLock的对比等,这些都能帮助用户进一步学习。 最后,检查是否符合用户的要求,比如使用中文,LaTeX格式正确,引用标识自然添加。确保没有使用Markdown格式,行内公式用$...$,独立公式用$$...$$,但根据示例,可能不需要数学公式,所以主要关注代码块的格式和引用位置。</think>### Java中synchronized代码块锁定对象的原理 #### 1. 锁定对象的核心机制 Java的`synchronized`代码块通过**内置锁(监视器锁)**实现同步,锁的粒度由开发者指定的对象决定。关键点如下: - **锁与对象绑定**:每个Java对象(包括类对象)都有一个内置锁,线程进入同步代码块时需先获取该对象的锁,退出时释放[^2][^4]。 - **锁的排他性**:同一时间只有一个线程能持有对象的锁,其他线程需阻塞等待[^1]。 #### 2. 锁定对象的三种典型场景 | 场景 | 锁定对象 | 锁的作用范围 | 示例代码片段 | |-------------------------|------------------------|---------------------------|---------------------------------------| | **实例对象锁** | `this`或实例变量 | 同一实例的同步代码块 | `synchronized(this) { ... }` | | **类对象锁** | `Class`对象 | 所有实例的同步代码块 | `synchronized(MyClass.class) { ... }` | | **任意共享对象锁** | 显式指定的对象 | 依赖对象的作用域 | `synchronized(sharedObj) { ... }` | #### 3. 原理详解 1. **实例对象锁** - 当使用`synchronized(this)`或同步非静态方法时,锁定的是当前实例对象。 - 例如: ```java public void func() { synchronized(this) { // 锁定当前实例 // 临界区代码 } } ``` 不同实例的线程不会互相阻塞,但同一实例的线程会竞争同一把锁[^1][^3]。 2. **类对象锁** - 当使用`synchronized(MyClass.class)`或同步静态方法时,锁定的是类的`Class`对象。 - 例如: ```java public static void staticFunc() { synchronized(MyClass.class) { // 锁定类对象 // 临界区代码 } } ``` 所有实例的线程访问此代码块时都会竞争同一把锁[^4]。 3. **锁的获取与释放** - 通过`monitorenter`和`monitorexit`字节码指令实现(JVM层面)。 - 锁支持**可重入性**:线程可重复获取已持有的锁,计数器递增[^2]。 #### 4. 性能与设计注意事项 - **锁粒度**:过粗的锁(如类锁)会降低并发性能,需根据场景选择合适对象[^4]。 - **死锁风险**:多个线程互相等待对方持有的锁时可能引发死锁,需避免嵌套锁的交叉获取。 - **替代方案**:高并发场景可考虑`ReentrantLock`或并发容器。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值