JAVA多线程之常用方法

来源:互联网 发布:mac foobar2000 编辑:程序博客网 时间:2024/06/06 13:03

在多线程编程中,经常会使用到如下方法:

1. public final void wait()  throws InterruptedException,IllegalMonitorStateException

该方法用来将当前线程置入休眠状态,直到接到通知或被中断为止。在调用wait()之前,线程必须要获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait()方法。进入wait()方法后,当前线程释放锁。在从wait()返回前,线程与其他线程竞争重新获得锁。如果调用wait()时,没有持有适当的锁,则抛出IllegalMonitorStateException,它是RuntimeException的一个子类,因此,不需要try-catch结构。

注意事项1:

waite()和notify()必须在synchronized函数或synchronized block中进行调用。如果在non-synchronized函数或non-synchronized block中进行调用,虽然能编译通过,但在运行时会发生IllegalMonitorStateException的异常。 

注意事项2:

当我们调用wait的时候,语法是这样的:

obj.wait();

但是真正wait的不是obj,而是当前正在使用obj的线程。

2. public final native void notify() throws IllegalMonitorStateException

Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. 

The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object (这句话的意思是被唤醒的线程不一定就能获取对象的monitor); for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.

This method should only be called by a thread that is the owner of this object's monitor. A thread becomes the owner of the object's monitor in one of three ways:

  1. By executing a synchronized instance method of that object.
  2. By executing the body of a synchronized statement that synchronizes on the object.
  3. For objects of type Class, by executing a synchronized static method of that class.
  4. Only one thread at a time can own an object's monitor.

这里的注意事项和wait一样。

3. public final native void notifyAll() throws IllegalMonitorStateException
notifyAll使所有原来在该对象上wait的线程统统退出wait的状态(即全部被唤醒,不再等待notify或notifyAll,但由于此时还没有获取到该对象锁,因此还不能继续往下执行),变成等待获取该对象上的锁,一旦该对象锁被释放(notifyAll线程退出调用了notifyAll的synchronized代码块的时候),他们就会去竞争。如果其中一个线程获得了该对象锁,它就会继续往下执行,在它退出synchronized代码块,释放锁后,其他的已经被唤醒的线程将会继续竞争获取该锁,一直进行下去,直到所有被唤醒的线程都执行完毕。

4. public final void wait(long timeout) throws InterruptedException

Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed. The current thread must own this object's monitor.
This method causes the current thread (call it T) to place itself in the wait set for this object and then to relinquish any and all synchronization claims on this object. Thread T becomes disabled for thread scheduling purposes and lies dormant until one of four things happens:

  1. Some other thread invokes the notify method for this object and thread T happens to be arbitrarily chosen as the thread to be awakened.
  2. Some other thread invokes the notifyAll method for this object.
  3. Some other thread interrupts thread T.
  4. The specified amount of real time has elapsed, more or less. If timeout is zero, however, then real time is not taken into consideration and the thread simply waits until notified.
The thread T is then removed from the wait set for this object and re-enabled for thread scheduling. It then competes in the usual manner with other threads for the right to synchronize on the object; once it has gained control of the object, all its synchronization claims on the object are restored to the status quo ante - that is, to the situation as of the time that the wait method was invoked. Thread T then returns from the invocation of the wait method. Thus, on return from the wait method, the synchronization state of the object and of thread T is exactly as it was when the wait method was invoked.

注意:以上四个方法都是来自Object类。

5. public final void join() throws InterruptedException

线程的合并的含义就是将几个并行线程的线程合并为一个单线程执行,应用场景是当一个线程必须等待另一个线程执行完毕才能执行时,Thread类提供了join方法来完成这个功能,注意,它不是静态方法。
从上面的方法的列表可以看到,它有3个重载的方法:
void join()    
    当前线程等该加入该线程后面,等待该线程终止。    
void join(long millis)    
    当前线程等待该线程终止的时间最长为 millis 毫秒。 如果在millis时间内,该线程没有执行完,那么当前线程进入就绪状态,重新等待cpu调度   

举例:

public static void main(String[] args) {

     MyThread t = new MyThread();

     t.start();

    // t.join();

     System.out.println("End");

}

在上面这个例子里总共有两个线程:一个是主线程,一个是t线程。主线程和t线程是互相竞争cpu的,所以如果在MyThread里的run方法要执行很长时间才能结束的话,那么“End”就一定会在run()方法完全结束以前被打印出来。如果你想让run方法执行完才打印"End",那么你就得调用 t.join()。

6. public static void sleep(long millis) throws InterruptedException

Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers. The thread does not lose ownership of any monitors.

注意加粗那段话,这是sleep 和 wait的一个巨大的区别。假设线程A目前操作对象obj (线程A拥有该对象的锁), 通过sleep,虽然该线程让出了CPU,但是如果其它线程也需要使用对象obj,还得等着,但是如果其它线程不需要使用对象obj,那么CPU就可以执行其它线程。但是wait既不会占用CPU并且还会释放obj的锁,这样其它线程可以对obj进行操作。

7. public static void yield()
A hint to the scheduler that the current thread is willing to yield its current use of a processor. The scheduler is free to ignore this hint.
注意下面这段话:

It is important to note that neither Thread.sleep nor Thread.yield have any synchronization semantics. In particular, the compiler does not have to flush writes cached in registers out to shared memory before a call to Thread.sleep or Thread.yield, nor does the compiler have to reload values cached in registers after a call to Thread.sleep or Thread.yield.

reference: 

http://blog.csdn.net/ns_code/article/details/17225469
http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp16
http://blog.csdn.net/lonelyroamer/article/details/7949969
http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html

0 0