多线程安全问题 本帖最后由 xuezhezhao 于 2012-11-24 14:30:22 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。 若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。上面的这些复制的。其实举一个简单例子,两个人同时操作两台ATM机,一个人往一个账号存钱,另一个取钱。存钱的获取原来的值为500,然后存入500,返回写入为1000,但是因为延迟还未写会,另一个速度快,提了500,返回应该为0,这时第一个再返回1000写入,这样等于结果还是1000.你那个程序我看了,已经加了sy锁了,应该就是线程安全的。去掉那个关键字,然后数据量调大一点,就会看到线程不安全的效果了。 这个要用到线程同步!比如自定义一个同步类:/** * 分子处理线程和数据库写入线程的同步信号量 * @author Administrator * */public class MySemaphore { private int count; public MySemaphore(int n) { this.count = n; } public synchronized void acquire() { count--; if(count<0){ try { wait(); } catch (InterruptedException e) { // keep trying } } } public synchronized void release() { count++; if(count>=0) notify(); // alert a thread that's blocking on this semaphore }} syn = new MySemaphore(N)//定义一个同步信号量syn.acquire();//关锁syn.release()//开锁 用同一个锁就行 Lock()看看“毕向东”的JavaSE class Resource{ private String name; private int count = 1; private boolean flag = false;// 创建一个锁对象。 Lock lock = new ReentrantLock(); //通过已有的锁获取该锁上的监视器对象。// Condition con = lock.newCondition(); //通过已有的锁获取两组监视器,一组监视生产者,一组监视消费者。 Condition producer_con = lock.newCondition(); Condition consumer_con = lock.newCondition(); public void set(String name)// t0 t1 { lock.lock(); try { while(flag)// try{lock.wait();}catch(InterruptedException e){}// t1 t0 try{producer_con.await();}catch(InterruptedException e){}// t1 t0 this.name = name + count;//烤鸭1 烤鸭2 烤鸭3 count++;//2 3 4 System.out.println(Thread.currentThread().getName()+"...生产者5.0..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3 flag = true;// notifyAll();// con.signalAll(); consumer_con.signal(); } finally { lock.unlock(); } } public void out()// t2 t3 { lock.lock(); try { while(!flag)// try{this.wait();}catch(InterruptedException e){} //t2 t3 try{cousumer_con.await();}catch(InterruptedException e){} //t2 t3 System.out.println(Thread.currentThread().getName()+"...消费者.5.0......."+this.name);//消费烤鸭1 flag = false;// notifyAll();// con.signalAll(); producer_con.signal(); } finally { lock.unlock(); } }}class Producer implements Runnable{ private Resource r; Producer(Resource r) { this.r = r; } public void run() { while(true) { r.set("烤鸭"); } }}class Consumer implements Runnable{ private Resource r; Consumer(Resource r) { this.r = r; } public void run() { while(true) { r.out(); } }}class ProducerConsumerDemo2{ public static void main(String[] args) { Resource r = new Resource(); Producer pro = new Producer(r); Consumer con = new Consumer(r); Thread t0 = new Thread(pro); Thread t1 = new Thread(pro); Thread t2 = new Thread(con); Thread t3 = new Thread(con); t0.start(); t1.start(); t2.start(); t3.start(); }}看看这个学习学习 把outInfo和setInfo中的else语句删除。就可以了。 楼主的问题是 setInfor()和OutInfor().楼主的代码: if(flag) /*如果flag值为false,则共享资源中没有信息,进行赋值 如果为true,则共享资源中有信息没有打印,不进行赋值,进行wait操作 */ { try { this.wait(); } catch (Exception e) { } } else { this.name = name; this.sex = sex; } flag=true; //改变开关,让输入程序不能再次进行赋值,同时可以让打印程序启动 this.notify();//唤醒输出线程当程序从wait()返回时是什么状态? 是输出线程将信息取走了,运行了notify(),使输入线程继续运行,这时输入线程应该进行赋值操作。而楼主的代码,却有else语句,直接跳过了赋值语句。那它就是保持原来的值,所以会出现连续的相同的值。把else 去掉即可。 if(flag) /*如果flag值为false,则共享资源中没有信息,进行赋值 如果为true,则共享资源中有信息没有打印,不进行赋值,进行wait操作 */ { try { this.wait(); } catch (Exception e) { } } //else //{ //唤醒后执行此赋值操作。 this.name = name; this.sex = sex; //} flag=true; //改变开关,让输入程序不能再次进行赋值,同时可以让打印程序启动 this.notify();//唤醒输出线程下面的输出线程也一样改一下。 if (!flag)//如果flag值为ture,则共享资源中有信息,进行打印,否则等待 { try { this.wait(); } catch (Exception e) { } } //else //{ System.out.println(name+"......"+sex); //} flag=false; //改变开关,让输入程序可以进行赋值,同时让自己不能在打印 this.notify();//唤醒输 中!!~哥们你说的太对了。/*线程共享资源类,信息类*/class ResourceWaitNotifyDemo{ private String name; private String sex; private boolean flag=false;/* 为什么用了显式的if...else结构,多线程就不安全了呢?Why?~Why????。 public synchronized void setInfo(String name,String sex)//信息输入函数 { if(flag) { try{this.wait();}catch(Exception e){} } else { this.name = name; this.sex = sex; flag=true; //改变开关,让输入程序不能再次进行赋值,同时可以让打印程序启动 this.notify();//唤醒输出线程 } }*/ /*线程安全代码*/ public synchronized void setInfo(String name,String sex)//信息输入函数 { if(flag) try{this.wait();}catch(Exception e){} this.name = name; this.sex = sex; flag=true; //改变开关,让输入程序不能再次进行赋值,同时可以让打印程序启动 this.notify();//唤醒输出线程 } public synchronized void OutInfo()//信息输出函数 { if(!flag)//如果flag值为ture,则共享资源中有信息,进行打印,否则等待 { try { this.wait(); } catch (Exception e) { } } else { System.out.println(name+"......"+sex); flag=false; //改变开关,让输入程序可以进行赋值,同时让自己不能在打印 this.notify();//唤醒输入线程 } }} 哥们我就觉得这个If...else有问题。看看我回复的那个代码,那里用的是隐式的if...else吗? “哥们我就觉得这个If...else有问题。看看我回复的那个代码,那里用的是隐式的if...else吗?”我看不是隐式的if else. 没有else了。(else 是一旦if条件成立,就不执行了。而现在的是不管if成立与否,都要执行。以前看见书上说,(论坛里也很多人建议,不要用if(),而用while()更好。建议楼主试试。 一个java难题 是否enum不被tomcat5支持? jtable怎样设置某列的值不能被修改,整张表呢?某个元素被修改后,怎样取处修改后的值? 勇闯黄金十二宫--天秤宫 如何将Tue Jun 01 16:25:01 CST 2004转换成 Date型 集思广益----想做一个由购物车功能的网站,有什么做最方便? 问一个查询数据库的问题 有关数据库连接池的问题 为何提示class JTabbedPane not found? Netty如何获得本次请求对应的应答 新手求教一个类型转换的问题 组成最小的数
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。
上面的这些复制的。
其实举一个简单例子,两个人同时操作两台ATM机,一个人往一个账号存钱,另一个取钱。
存钱的获取原来的值为500,然后存入500,返回写入为1000,但是因为延迟还未写会,
另一个速度快,提了500,返回应该为0,这时第一个再返回1000写入,这样等于结果还是1000.
你那个程序我看了,已经加了sy锁了,应该就是线程安全的。
去掉那个关键字,然后数据量调大一点,就会看到线程不安全的效果了。
比如自定义一个同步类:
/**
* 分子处理线程和数据库写入线程的同步信号量
* @author Administrator
*
*/
public class MySemaphore {
private int count; public MySemaphore(int n) {
this.count = n;
} public synchronized void acquire() {
count--;
if(count<0){
try {
wait();
} catch (InterruptedException e) {
// keep trying
}
}
} public synchronized void release() {
count++;
if(count>=0)
notify(); // alert a thread that's blocking on this semaphore
}
}
syn.acquire();//关锁
syn.release()//开锁
看看“毕向东”的JavaSE
class Resource
{
private String name;
private int count = 1;
private boolean flag = false;// 创建一个锁对象。
Lock lock = new ReentrantLock(); //通过已有的锁获取该锁上的监视器对象。
// Condition con = lock.newCondition(); //通过已有的锁获取两组监视器,一组监视生产者,一组监视消费者。
Condition producer_con = lock.newCondition();
Condition consumer_con = lock.newCondition();
public void set(String name)// t0 t1
{
lock.lock();
try
{
while(flag)
// try{lock.wait();}catch(InterruptedException e){}// t1 t0
try{producer_con.await();}catch(InterruptedException e){}// t1 t0
this.name = name + count;//烤鸭1 烤鸭2 烤鸭3
count++;//2 3 4
System.out.println(Thread.currentThread().getName()+"...生产者5.0..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3
flag = true;
// notifyAll();
// con.signalAll();
consumer_con.signal();
}
finally
{
lock.unlock();
}
} public void out()// t2 t3
{
lock.lock();
try
{
while(!flag)
// try{this.wait();}catch(InterruptedException e){} //t2 t3
try{cousumer_con.await();}catch(InterruptedException e){} //t2 t3
System.out.println(Thread.currentThread().getName()+"...消费者.5.0......."+this.name);//消费烤鸭1
flag = false;
// notifyAll();
// con.signalAll();
producer_con.signal();
}
finally
{
lock.unlock();
}
}
}class Producer implements Runnable
{
private Resource r;
Producer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.set("烤鸭");
}
}
}class Consumer implements Runnable
{
private Resource r;
Consumer(Resource r)
{
this.r = r;
}
public void run()
{
while(true)
{
r.out();
}
}
}class ProducerConsumerDemo2
{
public static void main(String[] args)
{
Resource r = new Resource();
Producer pro = new Producer(r);
Consumer con = new Consumer(r); Thread t0 = new Thread(pro);
Thread t1 = new Thread(pro);
Thread t2 = new Thread(con);
Thread t3 = new Thread(con);
t0.start();
t1.start();
t2.start();
t3.start(); }
}看看这个学习学习
楼主的代码:
if(flag)
/*如果flag值为false,则共享资源中没有信息,进行赋值
如果为true,则共享资源中有信息没有打印,不进行赋值,进行wait操作
*/
{
try
{
this.wait();
}
catch (Exception e)
{
}
}
else
{
this.name = name;
this.sex = sex;
}
flag=true; //改变开关,让输入程序不能再次进行赋值,同时可以让打印程序启动
this.notify();//唤醒输出线程
当程序从wait()返回时是什么状态? 是输出线程将信息取走了,运行了notify(),使输入线程继续运行,这时输入线程应该进行赋值操作。而楼主的代码,却有else语句,直接跳过了赋值语句。那它就是保持原来的值,所以会出现连续的相同的值。
把else 去掉即可。
if(flag)
/*如果flag值为false,则共享资源中没有信息,进行赋值
如果为true,则共享资源中有信息没有打印,不进行赋值,进行wait操作
*/
{
try
{
this.wait();
}
catch (Exception e)
{
}
}
//else
//{ //唤醒后执行此赋值操作。
this.name = name;
this.sex = sex;
//}
flag=true; //改变开关,让输入程序不能再次进行赋值,同时可以让打印程序启动
this.notify();//唤醒输出线程
下面的输出线程也一样改一下。
if (!flag)//如果flag值为ture,则共享资源中有信息,进行打印,否则等待
{
try
{
this.wait();
}
catch (Exception e)
{
}
}
//else
//{
System.out.println(name+"......"+sex);
//}
flag=false; //改变开关,让输入程序可以进行赋值,同时让自己不能在打印
this.notify();//唤醒输
中!!~哥们你说的太对了。/*线程共享资源类,信息类*/
class ResourceWaitNotifyDemo
{
private String name;
private String sex;
private boolean flag=false;/*
为什么用了显式的if...else结构,多线程就不安全了呢?Why?~Why????。 public synchronized void setInfo(String name,String sex)//信息输入函数
{
if(flag)
{
try{this.wait();}catch(Exception e){}
}
else
{
this.name = name;
this.sex = sex;
flag=true; //改变开关,让输入程序不能再次进行赋值,同时可以让打印程序启动
this.notify();//唤醒输出线程
}
}
*/
/*线程安全代码*/
public synchronized void setInfo(String name,String sex)//信息输入函数
{
if(flag)
try{this.wait();}catch(Exception e){}
this.name = name;
this.sex = sex;
flag=true; //改变开关,让输入程序不能再次进行赋值,同时可以让打印程序启动
this.notify();//唤醒输出线程
} public synchronized void OutInfo()//信息输出函数
{
if(!flag)//如果flag值为ture,则共享资源中有信息,进行打印,否则等待
{
try
{
this.wait();
}
catch (Exception e)
{
}
}
else
{
System.out.println(name+"......"+sex);
flag=false; //改变开关,让输入程序可以进行赋值,同时让自己不能在打印
this.notify();//唤醒输入线程
}
}
}
哥们我就觉得这个If...else有问题。看看我回复的那个代码,那里用的是隐式的if...else吗?
以前看见书上说,(论坛里也很多人建议,不要用if(),而用while()更好。建议楼主试试。