黑马程序员技术交流社区

标题: 多线程通信问题分享 [打印本页]

作者: 胡卿    时间: 2012-6-16 01:49
标题: 多线程通信问题分享
等待/唤醒机制。

1,同步。
2,wait,notify,notifyAll方法。

wait,notify,notifyAll这样的方法都属于监视器方法。
监视器你可以理解成就是那个锁。
这些方法用于操作持有该锁的线程。

一个锁对应一组监视器方法。

这些方法必须定义在同步中,并明确所在同步的锁。
简单说,这些方法必须要被锁对象调用。

---------------
生产者消费者,

如果只有一个生产者,一个消费者的,
那么可以通过 if判断标记,同时使用wait notify方法来完成等待唤醒。

当有多个生产者和消费者时,
如果通过这种方式,会出现,数据错误。 比如:一个生产者生产了两次,而只被消费一次。
问题产生的原因:本方被本方唤醒后,没有判断标记,也不清楚本方是否有执行,就进行了一次执行。
会导致之前的执行的有可能无效。

解决:必须让每次被唤醒的线程都判断一次标记。所以通过while循环来判断标记。

当循环判断标记后:发现,程序居然死锁了(程序没结束当无法继续执行。)
问题原因: 还是本方唤醒本方造成的,被唤醒的本方判断完标记后,有可能继续等待。导致了所有线程都等待。
解决:为了本方唤醒对象,而又没有直接方法完成,所以就使用过了notifyAll,将所有等待线程唤醒,
如果本方线程被唤醒,继续等,但是对方也被唤醒了,这就有了执行的机会。

所以多个生产者和消费者的解决方案就是 循环判断标记while,和notifyAll。

到了JDK1.5的时候,有了对锁和监视器的升级对象。

在java.util.concurrent.locks包中。
提供了两个对象 Lock Condition.

Lock接口替换了synchronized
同步函数或者同步代码块,对锁的操作是隐式的,并不直观。
而Lock将锁封装成了一个单独的对象,该对象具备获取锁和释放锁的方法。
也就是对锁的操作是显示。
Lock
lock():获取锁。
unlock():释放锁。

注意:锁本身也是一种资源。释放锁动作必须要执行。所以一般定义在finally代码块中。


Condition:以前监视器方法封装到了Object对象中,任意锁对象都可以使用。
  现在将监视器方法封装到了Condition对象中。而Condition是通过Lock对象来获取的。
  Lock对象可以绑定Condition.
监视器方法:
  await();
  signal():
  signalAll():


这样就可以把原来的代码都用新对象来表示。
而且新对象提供了一个对多生产者消费者的解决方案。
Lock对象上,可以绑定多组监视器对象。
就可以实现本方只唤醒对象的操作。


public synchronized void set()
{
    while(b)
    wait();

    code....;
    b = true;
    notifyAll();

}
public synchronized void out()
{
    while(!b)
    wait();
    code....;
    b = false;
    notifyAll();
}

--
以上代码进行jdk1.5版本的改写。

//明确锁对象,而且明确监视器对象。和以前不同的是,
//Lock对象可以有多组监视器。
Lock lock = new ReentrantLock();
//生产者的监视器。
Condition con1 = lock.newCondition();
//消费者的监视器。
Condition con2 = lock.newCondition();


Thread-0   Thread-1
public void set()
{
    lock.lock();
    try
   {
       while(b)
      con1.await();

      code....;
      b = true;
      con2.signal();

   }
finally
  {
      lock.unlock();
  }

}

Thread-2  Thread-3
public void out()

{
   lock.lock();
   try

   {
        while(!b)
        con2.await();
        code....;
        b = false;
        con1.signal();
    }
   finally

    {
   lock.unlock();
    }
}


-------------------

sleep和wait的区别:
sleep:释放执行权,不释放锁。
wait:释放执行权,释放锁。



---------

停止线程:
1,定义标记。控制住run中的循环。
2,如果线程冻结,无法执行标记,强制将其恢复到运行状态,interrupt():
  该动作会放生异常。

守护线程:
setDaemon(boolean):当前台线程运行都结束了,后台线程无论是否执行完代码都会自动结束。

加入线程:
join():A线程执行到B线程的join方法是,A线程会释放执行权,等到B线程执行结束后,A在执行。
   B线程执行时,A线程处于冻结状态。






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2