一、当两个并发线程访问同一个对象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
分享到:
相关推荐
本文将深入探讨`synchronized`的几种使用示例,包括方法加锁、代码块加锁(针对`this`和对象)以及静态方法加锁。 1. **方法加锁** 当在实例方法前使用`synchronized`关键字时,它会锁定当前对象的监视器,只有...
下面,我们将从`synchronized`的基本概念、使用方式以及与`wait`和`notify`方法的关系几个方面进行详细阐述。 ### 一、`synchronized`关键字的基本概念 `synchronized`是Java语言中提供的关键字,用于控制线程的...
本节将通过几个具体的代码示例,逐步分析如何正确地使用`synchronized`关键字来解决线程同步问题。 ##### 3.1 错误的同步尝试 首先,考虑以下错误的实现方式: ```java class MyThread implements Runnable { ...
synchronized (this) { // 互斥区 } } ``` Java线程安全和锁Synchronized知识点详解是Java开发中非常重要的一部分,正确地使用synchronized关键字可以确保多线程环境下的数据安全,避免数据不一致或数据污染等...
1. 在方法声明上使用:`synchronized` 关键字放在方法前,表示同一时刻只有一个线程能执行该方法,其他线程需等待。这获取的是对象的监视器锁(成员锁)。 示例: ```java public class MyClass { public ...
线程的生命周期分为以下几个阶段: - **新建**:当一个线程被创建但尚未启动时,处于新建状态。 - **就绪**:调用`start()`方法后,线程进入就绪状态,等待CPU分配时间片。 - **运行**:线程获得CPU时间片后,开始...
下面通过几个示例来深入理解JSP的基本语法和功能: **示例1:求1到100的和** ```jsp ;charset=GB2312" %> 这是一个简单的JSP页面 int i, sum = 0; for (i = 1; i ; i++) { sum = sum + i; } %> <P>1到100的...
- 当多个线程尝试同时访问被`synchronized`修饰的方法或代码块时,只有一个线程能获得锁并进入。 - 其他线程必须等待锁释放才能继续。 2. **显式锁(ReentrantLock)**: - 提供了更灵活的锁定机制,如可中断锁...
以下是对这几个示例的详细解析: #### 二、示例详解 ##### 示例1: 简单的数字求和 **文件名:** Example1_1.jsp **代码解析:** ```jsp ;charset=GB2312"%> һJSPҳ int i, sum = 0; for (i = 1; i ; i++) { ...
**Strings="a"+"b"+"c"内存创建了几个对象** - 字符串拼接过程中创建对象的数量取决于拼接方式。 - 示例代码说明不同拼接方式下对象创建的数量。 **String类为什么复写Object类的equals方法** - `equals`方法用于...
- 同步代码块更灵活,可以指定要锁定的对象,例如`synchronized(this)`或`synchronized(obj)`。 2. ** volatile 关键字**: - `volatile` 关键字确保了共享变量的可见性,即当一个线程修改了volatile变量的值,...
### 编写一个JAVA的队列类 #### 概述 队列是一种基本的数据结构,遵循先进先出(FIFO)原则,即最先加入队列的元素将最先被移除。...此外,还提供了一个简单的使用示例,帮助读者更好地理解队列的使用方式。
根据给定文件中的标题、描述、部分内容,我们可以总结出几个重要的知识点,主要集中在Java图形用户界面(GUI)设计、面向对象编程(OOP)的概念、异常处理机制、类与对象的使用、多线程编程等方面。 ### 图形用户...
在Java中实现令牌桶,通常需要以下几个关键组件: 1. **令牌桶**:存储令牌的容器,可以设定桶的容量和当前的令牌数量。 2. **令牌生成器**:按照固定速率生成并添加令牌到桶中。 3. **请求处理逻辑**:当请求到来时...
- 当一个线程进入`synchronized`修饰的方法或代码块时,其他试图进入该方法或代码块的线程将会被阻塞,直到第一个线程退出。 - 对于静态方法和对象方法而言,它们的锁对象分别是类对象和当前对象。 示例代码如下...
- 当一个类的实例只能有几个不同状态组合中的一种时。 - 为了避免创建一个与产品类层次平行的工厂类层次时。 **示例代码**: ```java // Prototype public interface Shape { Shape clone(); } // ...
这里有几个关键点: - 使用 `synchronized` 关键字确保线程安全。 - 使用 `wait()` 和 `notifyAll()` 方法来协调生产者和消费者之间的工作流。 - 通过检查队列的大小来判断是否可以继续生产和消费消息。 #### 3. **...
下面将详细介绍Java中常见的几种设计模式,并通过具体示例进行讲解。 1. 单例模式(Singleton): 单例模式确保一个类只有一个实例,并提供一个全局访问点。在Java中,可以通过双重检查锁定(Double-Checked ...