java如何实现数据的同步--多线程
经常会遇到一个这样的问题:如何实现 判断一个内存对象如Vector 是否有数据,如果有数据 就及时的 读取出来?
常用的普通方法是 用一个 while()循环 这个 Vector是否有数据,如果有数据 才读取。 但是 这种方法 占用的资源
多,效率不高。
以下教你 如何 用JAVA的wait(),notify(),notifyAll(),结合多线程来实现 上面的问题。java对象都会有一个wait(),
notify(),notifyAll(),3个方法,是因为JAVA在设计时就已经考虑了 对象的同步问题, 我们要上面的问题 也就是 如何
同步Vector的问题。 java的同步机制 就 需要用到一个 概念 (对象锁),即用 synchronized 来实现同步。
底下就一个详细的好例子,:::,
package com.netphonebook.base.thread;
import java.util.Vector;
public class TestWaitAndNotify {
public Vector v;
public TestWaitAndNotify() {
v = new Vector();
}
public static void main(String[] args) {
TestWaitAndNotify test = new TestWaitAndNotify();
Thread t1 = new Thread(new addThread(test.v),"add's thread");
Thread t2 = new Thread(new deleteThread(test.v),"delte's thread");
t1.start();
t2.start();
}
}
class addThread implements Runnable {
private Vector v;
public addThread(Vector v) {
this.v = v;
}
public void run() {
int i = 10;
while (i-- > 0) {
synchronized (this.v) {
if (this.v.size() == 0) {
this.v.addElement(new String("测试"));
System.out.println("线程:"+Thread.currentThread().getName()+" 已经添加完毕。");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.v.notifyAll();
} else {
try {
System.out.println("线程:"+Thread.currentThread().getName()+" 开始等待。。。");
this.v.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
class deleteThread implements Runnable {
private Vector v;
public deleteThread(Vector v) {
this.v = v;
}
public void run() {
int i = 10;
while (i-- > 0) {
synchronized (this.v) {
if (this.v.size() != 0) {
this.v.removeAllElements();
System.out.println("线程:"+Thread.currentThread().getName()+" 已经删除完毕。");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.v.notifyAll();
} else {
try {
System.out.println("线程:"+Thread.currentThread().getName()+" 开始等待。。。");
this.v.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
继续深入研究多线程。。。我把今天的成果给大家介绍介绍,相信大家以后要是有用得到多线程 处理数据同步的时候,肯定会用的上的。。。
之前我们说到用 synchronized关键字可以 结合 对象Object的wait(),notify(),可以实现数据的同步。
但是这种同步只能针对于synchronized(){...}模块里面的。如果要实现一个 流程同步 那么单单靠synchronized(){}
是不足实现的。什么叫流程同步,就比如:银行取款,查询,存款,这是一个必须要独立运行的,也就是说,3个
操作是要一起完成的。或者象 数据库的同步,先删除再插入 两个操作要绑定一起运行。
下面举个简单的例子:
本例中 我们这儿编写一个新的Account类,ATM类来模拟自动提款机,通过一个ATMTester的类,生成10个ATM线程,
同时对John账户进行查询、提款和存款操作(备注:某个银行帐户account,在ATM操作时,我们不排除在同一个时刻
可能会有相同的银行帐号在进行取款,存款,查询3个操作。)
本人思路:
1、多线程操作同一个数据时,若要实现数据的同步,就需要用到一个对象锁机制,object.wait(),object.notify()
注意,这个对象,应该叫实例(new Object()),其中wait(),notify()要对应,不能instance1.wait(),instance2.notify(),
这样子肯定报错。也就是实例A等待了,就必须要用实例A亲自去唤醒。(这个是初学者经常犯的错误),理解了
第一点,我们再看第二点。
2、封装一个对象lock,把这个对象当成锁,这样就可以把这个锁 当成工具,再来锁别的数据。这个锁主要有两个方法,
一个是上锁,一个解锁。拥有这个所的对象实例A,一旦上锁了,其他别的线程是不能够访问到这个对象实例A,只有
开了锁,其他的线程才有机会去访问这个对象实例A。
3、我们封装的这个对象lock,可以用来锁住当前登陆的银行帐户,当用户一登陆就上锁,只有等帐户退出了才解锁。这样
肯定可以确保不同线程的数据同步。
首先,我们来看看如何封装这个对象锁,当成工具锁。package com.netphonebook.base.thread.sync;
public class MyLock {
private Thread currentT = null;
//上锁方法
public synchronized void lock(){
System.out.println("******************上锁(开始)*******************"+Thread.currentThread().getName());
System.out.println("进入的当前线程:"+Thread.currentThread().getName());
System.out.println("当前忙碌线程:"+currentT);
if(currentT == null){
currentT = Thread.currentThread();
}
if(currentT != Thread.currentThread()){
try {
System.out.println("忙的线程:"+ currentT.getName()+" 现在是 " + Thread.currentThread().getName() +" 等待。");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//重点,上段代码是一个等待堵塞过程,一旦这个堵塞过程结束了,也就是有线程给notify唤醒了,所以把这个当前个唤醒的
//线程又赋值给currentT
if(currentT == null){
currentT = Thread.currentThread();
}
System.out.println("******************上锁(结束)*******************"+Thread.currentThread().getName());
}
//解锁方法
public synchronized void unLock(){
System.out.println("----------开始解锁----------"+Thread.currentThread().getName());
System.out.println("当前忙碌线程:"+currentT);
if(currentT == Thread.currentThread()){
currentT = null;
notify();
}
System.out.println("----------结束解锁----------"+Thread.currentThread().getName());
}
}
其他源码请下载:synchro.rar