通常情况下,程序中的多个线程是互相协调和互相联系的,多线程之间有互斥和同步。
1.线程互斥
多个线程之间有共享资源(shared resource)时会出现互斥现象。
设有若干线程共享某个变量,而且都对变量有修改。如果它们之间不考虑相互协调工作,就会产生混乱。比如,线程A和B共用变量x,都对x执行增1操作。由于A和B没有协调,两线程对x的读取、修改和写入操作相互交叉,可能两个线程读取相同个x值,一个线程将修改后的x新值写入到x后,另一个线程也把自己对x修改后的新值写入到x。这样,x只记录后一个线程的修改作用。
临界段:多线程互斥使用共享资源的程序段,在操作系统中称为临界段。临界段是一种加锁的机制,与多线程共享资源有关。
临界段的作用是在任何时刻一个共享资源只能供一个线程使用。当资源未被占用,线程可以进入处理这个资源的临界段,从而得到该资源的使用权;当线程执行完毕,便退出临界段。如果一个线程已进入某个共享资源,并且还没有使用结束,其他线程必须等待。
在JAVA中使用关键字synchronized定义临界段,能对共享对象进行上锁操作。
2.线程同步
多线程之间除了有互斥情况外,还有线程同步。当线程A使用某个对象,而此对象又需要线程B修改后才能符合本线程的需要,此时线程A就要等待线程B完成修改工作。这种线程相互等待称为线程的同步。
为实现同步,JAVA语言提供了wait()、notify()和notifyAll()三个方法供线程在临界段中使用。
在临界段中使用wait()方法,使执行该方法的线程等待,并允许其他线程使用这个临界段。wait()常用两种格式:
wait()——让线程一直处于等待队列,知道被使用了notify()或notifyAll()方法唤醒。
wait(long timeout)——让线程等待到被唤醒,或经过指定时间后结束等待。
当线程使用完临界段后,用notify()方法通知由于想使用这个临界段而处于等待状态的线程结束等待。notify()方法只是通知第一个处于等待的线程。
如果某个线程在使用完临界段方法后,其他早先等待的线程都可以结束等待,一起重新竞争CPU,则可以使用notifyAll()方法。