天天看点

java笔记六:线程间的协调

  比如说在银行开个账户会有一个存折和一张卡,如果某一天同一时间丈夫拿着存折去

柜台取钱,而妻子拿着银行卡去atm取钱。当丈夫查询余额里面有3000元,正准备取2000元,这时候妻子也到atm里面查询也有3000,也取

2000元。其实银行不可能让我们这么做,如果这样的话那我们天天取钱去了,还搞什么工作啊。其实在丈夫查询的时候已经对该账号上了锁,另外的银行卡要取

钱的话必须等待该锁被释放。下面用一个程序模拟这个例子:

  上面的例子如果在getmoney()方法上面不加synchronized关键字的话,输出结果为:

wife取走了2000元

husband取走了2000元

  而加上synchronized后,输出结果为:

对不起,您的余额不足!

  上面两种情况说明,如果多个线程同时访问某个资源,而不给该资源枷锁的话,就会出现问题。而加上synchronized关键字后就可以避免这种错误发生了。它能够保证只有一个线程能够访问getmoney()这个方法,其他药访问该方法的线程必须等待。

锁住某个资源可以用synchronized关键字来修饰一个方法或者同步代码块,这样能保证同一时间只能由一个线程访问该资源。

    ①、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

      ②、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

        ③、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

  我们都知道,操作系统中多个进程之间如果不进行协调就很容易出现死锁的情况,死锁的四个条件:互斥、占有等待、非剥夺、循环等待。我们只要破坏其中一个条件就能避免死锁发生。线程之间也容易出现死锁,下面这个例子就演示了死锁的情况:

  运行程序输出1    0后就进入死锁状态,该程序永远也不会停止,因为两个线程同时处于等待状态。线程t1锁住了o1对象,等待o2对象,而线程t2锁住o2等待o2对象,谁也不让谁,这就进入了一个循环占有等待的情况了,死锁也就出现了。

  所以,如果多个线程如果不进行协调的话很容易出现死锁的问题。操作系统中使用进程调度来协调各个进程,那么java重如何对各个线程进行协调呢?

  java中主要使用object类中的wait()、notify()、notifyall()方法来协调各个线程。典型的例子有哲学家吃饭问题、生产者和消费者问题、理发师问题。下面一个用一个例子来演示生产者和消费者问题。

  问题描述:生产者负责做馒头,做好馒头后放进指定的篓子里面,消费者消费该篓子里面的馒头。篓子里只能装一定量的馒头,满了以后生产者必须进入等待状态,消费者吃完馒头后也必须进入等待状态。

  wait()、notify()、notifyall()方法的作用:

    notify():唤醒在此对象监视器上等待的单个线程。

    notifyall():唤醒在此对象监视器上等待的所有线程。

  wait()与sleep()的区别:

    两个方法的共同点就是让当前线程进入等待状态。

    不同点:

    wait()之后,锁就不归我所有了,必须等醒过来后才能拥有该锁,并且必须要有人唤醒它才会醒过来

sleep()不同,锁还是归我所有,一段时间后会自动醒过来