码迷,mamicode.com
首页 > 编程语言 > 详细

线程通信

时间:2016-06-05 17:14:34      阅读:220      评论:0      收藏:0      [点我收藏+]

标签:多线程通信(等到唤醒机制)问题


讲解等待唤醒机制之前,有必要搞清一个概念——

线程之间的通信:

多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制。


等待唤醒机制所涉及到的方法:


wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。


notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。


notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。


  

public class NumberHolder
{    private int number;    public synchronized void increase()
    {        if (0 != number)
        {            try
            {
                wait();
            }            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }        // 能执行到这里说明已经被唤醒        // 并且number为0
        number++;
        System.out.println(number);        // 通知在等待的线程        notify();
    }    public synchronized void decrease()
    {        if (0 == number)
        {            try
            {
                wait();
            }            catch (InterruptedException e)
            {
                e.printStackTrace();
            }

        }        // 能执行到这里说明已经被唤醒        // 并且number不为0
        number--;
        System.out.println(number);
        notify();
    }

}public class IncreaseThread extends Thread
{    private NumberHolder numberHolder;    public IncreaseThread(NumberHolder numberHolder)
    {        this.numberHolder = numberHolder;
    }

    @Override    public void run()
    {        for (int i = 0; i < 20; ++i)
        {            // 进行一定的延时
            try
            {
                Thread.sleep((long) Math.random() * 1000);
            }            catch (InterruptedException e)
            {
                e.printStackTrace();
            }            // 进行增加操作            numberHolder.increase();
        }
    }

}public class DecreaseThread extends Thread
{    private NumberHolder numberHolder;    public DecreaseThread(NumberHolder numberHolder)
    {        this.numberHolder = numberHolder;
    }

    @Override    public void run()
    {        for (int i = 0; i < 20; ++i)
        {            // 进行一定的延时
            try
            {
                Thread.sleep((long) Math.random() * 1000);
            }            catch (InterruptedException e)
            {
                e.printStackTrace();
            }            // 进行减少操作            numberHolder.decrease();
        }
    }

}public class NumberTest
{    public static void main(String[] args)
    {
        NumberHolder numberHolder = new NumberHolder();
        
        Thread t1 = new IncreaseThread(numberHolder);
        Thread t2 = new DecreaseThread(numberHolder);
                
        t1.start();
        t2.start();
    }

}

因为就是两个线程所以就是可以互相切换,即必须是互相切换,但是如果是四个线程呢?会怎么样呢?

那么再来两个线程;

 即把其中的NumberTest类改为如下:

public class NumberTest
{    public static void main(String[] args)
    {
        NumberHolder numberHolder = new NumberHolder();
        
        Thread t1 = new IncreaseThread(numberHolder);
        Thread t2 = new DecreaseThread(numberHolder);
        
        Thread t3 = new IncreaseThread(numberHolder);
        Thread t4 = new DecreaseThread(numberHolder);
                
        t1.start();
        t2.start();
        
        t3.start();
        t4.start();
    }

}

为什么两个线程的时候执行结果正确而四个线程的时候就不对了呢?

  因为线程在wait()的时候,接收到其他线程的通知,即往下执行,不再进行判断。两个线程的情况下,唤醒的肯定是另一个线程;但是在多个线程的情况下,执行结果就会混乱无序

比如,一个可能的情况是,一个增加线程执行的时候,其他三个线程都在wait,这时候第一个线程调用了notify()方法,其他线程都将被唤醒,然后执行各自的增加或减少方法。

  解决的方法就是:在被唤醒之后仍然进行条件判断,去检查要改的数字是否满足条件,如果不满足条件就继续睡眠。把两个方法中的if改为while即可。

public class NumberHolder
{    private int number;    public synchronized void increase()
    {        while (0 != number)
        {            try
            {
                wait();
            }            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }        // 能执行到这里说明已经被唤醒        // 并且number为0
        number++;
        System.out.println(number);        // 通知在等待的线程        notify();
    }    public synchronized void decrease()
    {        while (0 == number)
        {            try
            {
                wait();
            }            catch (InterruptedException e)
            {
                e.printStackTrace();
            }

        }        // 能执行到这里说明已经被唤醒        // 并且number不为0
        number--;
        System.out.println(number);
        notify();
    }

}

这样就可以解决了线程的混乱的问题。

线程通信

标签:多线程通信(等到唤醒机制)问题

原文地址:http://lyinginsun.blog.51cto.com/11600060/1786265

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!