多线程安全有关问题

多线程安全问题本帖最后由 xuezhezhao 于 2012-11-24 14:30:22 编辑/*多线程_等待唤醒机制*//***需求:创建

多线程安全问题
本帖最后由 xuezhezhao 于 2012-11-24 14:30:22 编辑


/*多线程_等待唤醒机制*/

/**
*需求:创建两个线程,一个进行存储信息,一个进行打印信息。
*目的:程序输入一个"mike man"打印一个"mike man"
*   输入一个"莉莉 女女女女女"打印一个"莉莉 女女女女女"
*步骤:创建一个共享资源类RescourceWaitNotifyDemo
*创建输入线程类InputWaitNotifyDemo
*创建打印线程类OutputWaitNotifyDemo
*由主函数创建线程,并执行。
*问题:
*为什么会有线程安全问题?
*怎么解决?
*/

/*线程共享资源类,信息类*/
class ResourceWaitNotifyDemo //
{
private String name;
private String sex;
private boolean flag=false;


public synchronized void setInfo(String name,String sex)//信息输入函数
{
if(flag)
/*如果flag值为false,则共享资源中没有信息,进行赋值
  如果为true,则共享资源中有信息没有打印,不进行赋值,进行wait操作
*/
{
try
{
this.wait();
}
catch (Exception e)
{
}
}
else
{
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();//唤醒输入线程
}
}

/*输入线程*/
class InputWaitNotifyDemo implements Runnable
{
private ResourceWaitNotifyDemo r;//创建共享类引用

InputWaitNotifyDemo(ResourceWaitNotifyDemo r)
{
this.r = r;//接收共享类对象
}

public void run()
{
int x=0;
while(true)
{
if (x==0)
{
r.setInfo("mike","man");
}
else
{
r.setInfo("莉莉","女女女女女");
}
x=(x+1)%2;
}
}

}

/*输出线程*/
class OutputWaitNotifyDemo implements Runnable
{
private ResourceWaitNotifyDemo r;

OutputWaitNotifyDemo(ResourceWaitNotifyDemo r)
{
this.r = r;//和输入线程操作同一个共享类对象
}

public void run()
{
while (true)
{
r.OutInfo();
}
}
}

/*主函数*/
class ThreadWaitNotifyTest
{
public static void main(String[] args)
{
ResourceWaitNotifyDemo res = new ResourceWaitNotifyDemo();
/*
InputWaitNotifyDemo i = new InputWaitNotifyDemo(res);
OutputWaitNotifyDemo o = new OutputWaitNotifyDemo(res);

Thread t1 = new Thread(i);
Thread t2 = new Thread(o);

t1.start();
t2.start();
*/
new Thread(new InputWaitNotifyDemo(res)).start();//创建输入线程
new Thread(new OutputWaitNotifyDemo(res)).start();//创建打印线程
}
}


[最优解释]
引用:
不是,我这个线程是非安全的,我预想的结果是,程序自动输入一个,然后就打印一个,可是我这个程序的线程是非安全的,输入一片,输出一片,完全不是预想的那样。试问,怎么解决这个问题?

楼主的问题是 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();//唤醒输


[其他解释]
把outInfo和setInfo中的else语句删除。就可以了。
[其他解释]
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
 若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。
上面的这些复制的。
其实举一个简单例子,两个人同时操作两台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()//开锁
[其他解释]
xuexileha
[其他解释]
用同一个锁就行 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().
楼主的代码:
Java code?123456789101112131415161718……


中!!~哥们你说的太对了。

/*线程共享资源类,信息类*/
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();//唤醒输入线程
}
}
}


[其他解释]
引用:
引用:引用:不是,我这个线程是非安全的,我预想的结果是,程序自动输入一个,然后就打印一个,可是我这个程序的线程是非安全的,输入一片,输出一片,完全不是预想的那样。试问,怎么解决这个问题?
楼主的问题是 setInfor()和OutInfor().
楼主的代码:
Java code?1234567……


哥们我就觉得这个If...else有问题。看看我回复的那个代码,那里用的是隐式的if...else吗?
[其他解释]
“哥们我就觉得这个If...else有问题。看看我回复的那个代码,那里用的是隐式的if...else吗?”

我看不是隐式的if else. 没有else了。(else 是一旦if条件成立,就不执行了。而现在的是不管if成立与否,都要执行。
以前看见书上说,(论坛里也很多人建议,不要用if(),而用while()更好。建议楼主试试。
[其他解释]
引用:
“哥们我就觉得这个If...else有问题。看看我回复的那个代码,那里用的是隐式的if...else吗?”

我看不是隐式的if else. 没有else了。(else 是一旦if条件成立,就不执行了。而现在的是不管if成立与否,都要执行。
以前看见书上说,(论坛里也很多人建议,不要用if(),而用while()更好。建议楼主试试。


哥们分给你了