线程的对象同步也称为块同步,对象同步锁定的代码执行区域较小,并且能够精确地唤醒所要唤醒的等待线程。所以在使用线程间的通信时应该优先使用对象同步,对象同步比较难以使用。使用不好就回抛出java.lang.IllegalMonitorStateException异常,原因如下:
1.同步的对象必须是线程本身的类变量或者是同步的代码所在的类本身的引用(即this指针)。
2.同步的对象必须是一个对象,而不是一个原子类型对应的对象类型,如Boolean等。
下面给出了两个使用对象同步的经典例子,在实际使用时可以进行扩充,变为实现自己功能的代码.
1.在线程内部使用对象同步
public class ThreadObjectSynchTest {
public static void main(String[] args) {
OperateCompleteFlag u = new OperateCompleteFlag();
MyThread3 t1 = new MyThread3("线程A", u);
MyThread3 t2 = new MyThread3("线程B", u);
MyThread3 t3 = new MyThread3("线程C", u);
MyThread3 t4 = new MyThread3("线程D", u);
MyThread3 t5 = new MyThread3("线程E", u);
MyThread3 t6 = new MyThread3("线程F", u);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
class MyThread3 extends Thread {
private OperateCompleteFlag flag;
MyThread3(String name, OperateCompleteFlag user3) {
super(name);
this.flag = user3;
}
public void run() {
synchronized (flag) {
if (!flag.getIsEnd()) {
try {
flag.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
flag.setIsEnd(false);
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(10L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
synchronized (flag) {
//u.setCash(u.getCash()+y);
System.out.println(Thread.currentThread().getName()
+ "运行结束");
flag.setIsEnd(true);
flag.notify();
}
}
}
class OperateCompleteFlag {
public Boolean getIsEnd() {
return isEnd;
}
public void setIsEnd(Boolean isEnd) {
this.isEnd = isEnd;
}
private Boolean isEnd = true;
}
2.在普通类的方法中使用对象同步
public class ThreadObjectSynchTest2 {
public static void main(String[] args) {
Account u = new Account("张三", 100);
MyThread2 t1 = new MyThread2("线程A", u, 20);
MyThread2 t2 = new MyThread2("线程B", u, -60);
MyThread2 t3 = new MyThread2("线程C", u, -80);
MyThread2 t4 = new MyThread2("线程D", u, -30);
MyThread2 t5 = new MyThread2("线程E", u, 32);
MyThread2 t6 = new MyThread2("线程F", u, 21);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
class MyThread2 extends Thread {
private Account u;
private int y = 0;
MyThread2(String name, Account u, int y) {
super(name);
this.u = u;
this.y = y;
}
public void run() {
u.oper(y);
}
}
class Account {
private String code;
private int cash;
public int getCash() {
return cash;
}
public void setCash(int cash) {
this.cash = cash;
}
public Boolean getIsEnd() {
return isEnd;
}
public void setIsEnd(Boolean isEnd) {
this.isEnd = isEnd;
}
private Boolean isEnd = true;
Account(String code, int cash) {
this.code = code;
this.cash = cash;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
/**
* 业务方法
*
* @param x
* 添加x万元
*/
public void oper(int x) {
try {
synchronized (this) {
if (!isEnd) {
wait();
}
}
isEnd = false;
for (int i = 0; i < 10; i++) {
Thread.sleep(10L);
System.out.println(Thread.currentThread().getName());
}
synchronized (this) {
this.cash += x;
System.out.println(Thread.currentThread().getName()
+ "运行结束,增加“" + x + "”,当前用户账户余额为:" + cash);
isEnd = true;
this.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return "User{" + "code='" + code + '\'' + ", cash=" + cash + '}';
}
}
分享到:
相关推荐
《线程与内核对象的同步》 在多线程编程中,确保线程间的同步是至关重要的,以避免数据竞争和死锁等问题。本章主要探讨了通过内核对象实现线程同步的原理和方法,详细讲解了四种内核对象,分别是事件、等待定时器、...
### 实验二:线程的同步 #### 一、实验目的与背景介绍 在现代操作系统中,线程作为进程中的可调度实体,在多任务处理、提高程序效率方面扮演着极其重要的角色。本实验旨在深入理解线程与进程的概念,并通过实践...
本篇文章将深入探讨三种在C++中实现多线程同步的方法:事件对象、关键代码段和互斥对象。 首先,我们来看**事件对象**。事件对象是一种信号机制,用于线程间通信和同步。在Windows API中,CreateEvent函数创建一个...
除了进程和线程对象,Windows还提供了多种内核对象用于同步: 1. **事件**:事件对象可以是手动重置或自动重置,手动重置事件在被通知后需要手动恢复到未通知状态,而自动重置事件在释放一个等待线程后会自动回到未...
本文将深入探讨如何使用CEvent对象来实现线程间的同步。 CEvent类是MFC对Windows API中的`CreateEvent`函数的封装,用于创建一个事件对象,该对象可以被线程用来通信和同步。事件对象有两种状态:未设定(非信号...
标题"多线程数据同步"直指这一核心问题,而描述则具体提到了使用临界区对象作为解决方案之一。 线程同步是为了防止多个线程同时访问共享资源,导致数据的混乱。在Windows操作系统中,临界区对象是一种轻量级的同步...
例如,可能会有一个`CSyncObject`类型的成员变量,它代表了一个线程同步对象,如临界区或读写锁。这些头文件会定义如何初始化和使用这些同步对象,以及如何在多线程环境中调用它们来保护对共享资源的访问。 使用...
`main`函数中初始化了这些同步对象,并分别创建了消费者线程和两个生产者线程。每个线程都使用特定的参数启动,例如`message1`、`message2`和`message3`,这可能是用于区分不同线程身份的标识。 实验总结,通过这个...
本文将详细介绍如何通过临界区、互斥内核对象、事件内核对象和信号量内核对象来实现线程同步。 1. 临界区(Critical Section) 临界区是一种简单的线程同步方法,用于保护共享资源免受并发访问。在进入临界区之前,...
4. **竞态条件**:多个线程同时修改同一变量或对象,最终结果取决于线程的调度,可能会出现不可预测的结果。 为了解决这些问题,开发者需要采取相应的同步机制。在Java中,可以使用`synchronized`关键字来标记代码...
本教程将深入探讨四种常见的线程同步机制:事件对象、信号量、互斥量以及临界区,帮助开发者理解和掌握如何在VC++中安全地实现多线程通信。 一、事件对象 事件对象是Windows API中用于线程间通信的一种同步机制。它...
操作系统线程同步是多线程编程中的核心概念,旨在确保并发执行的线程在访问共享资源时不会引发数据不一致性和竞态条件。本实验报告详细探讨了这一主题,通过一个简单的银行账户转账的示例来揭示临界区问题及其解决...
2. **事件(Event)**:事件是一种信号对象,线程可以通过`WaitForSingleObject`或`WaitForMultipleObjects`函数等待某个事件的发生,当事件被触发时,等待的线程可以继续执行。 3. **互斥量(Mutex)**:互斥量与临界...
线程的同步互斥是多线程编程中的关键概念,主要用来解决并发执行时的数据安全问题。在Java、C++、Python等支持多线程的编程语言中,线程同步和互斥是确保程序正确性和数据一致性的重要手段。 线程是指在单一进程内...
互斥对象(Mutex)是实现线程同步的一种常见机制,尤其在MFC(Microsoft Foundation Classes)库中有着广泛的应用。本文将详细探讨如何在MFC工程中使用Mutex来实现线程同步。 1. **互斥对象(Mutex)基础** - 互斥...
1. **Mutex 类**:Mutex(互斥锁)是一种独占式的同步对象,确保同一时间只有一个线程能够访问资源。当一个线程获取到Mutex后,其他试图获取的线程会被阻塞,直到Mutex被释放。例如,你可以使用Mutex的`WaitOne()`...
1. **互斥量(Mutex)**:互斥量是一种独占式同步对象,一次只有一个线程可以拥有互斥量。当一个线程获得互斥量后,其他试图获取该互斥量的线程将被阻塞,直到拥有者释放它。在VC6.0中,可以通过`CreateMutex()`函数...
本文主要讨论了VC++6.0环境下多线程同步的几种方法,包括临界区、事件、信号量和互斥内核对象。 **临界区**是实现线程同步的基本手段之一,它确保在同一时刻只有一个线程能够访问特定的代码区域或资源。在VC++6.0中...
多线程同步机制在软件开发中扮演着至关重要的角色,特别是在多处理器系统或者并发执行的任务中,确保线程间的正确协作和数据一致性是必不可少的。VC++中提供了多种同步机制来处理多线程间的同步问题,其中Event是...