您的位置:首页 > 编程语言 > Java开发

Java线程基础一

2016-03-08 19:43 726 查看

1.Object#wait

调用线程
等待,并且只能在获取了这个对象(就是wait方法所属的对象)的锁(monitor)的线程中执行(This method can only be invoked by a thread which owns this object’s monitor),也就是说
调用此方法,线程必须先获取monitor
(否则抛出IllegalMonitorStateException)。并且调用wait方法之后,调用线程会释放对象的锁(monitor),当被唤醒或者interrupt后才会重新获取锁。

调用wait方法的线程可以被interrupt,所以在某些情况下(比如根据条件决定是否继续往下执行)就应该在loop中执行,以循环检查条件是否满足。原因如下(就是说,
在没有通知,没有中断或者并未超时的情况下,wait的线程仍然有可能wake up,尽管并不常见,但是还是必须循环检查条件是否满足
):A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops, like this one:

synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}


例子:Android中的HandlerThread.java

/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}

@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}

/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
if (!isAlive()) {
return null;
}

// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}


其中getLooper方法,在获取锁(wait方法所属的对象和锁都是this)的前提下,循环检查条件。

2.Object#notify()

notify方法也同wait一样,
当前线程必须先获取对象的锁(否则IllegalMonitorStateException)
。在当前线程调用此方法后,要等到当前线程释放对象的锁之后,被唤醒的线程才能继续(也就是当前线程先释放锁,被唤醒的线程后重新获取锁)。作用就是唤醒在锁对象wait的线程。

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. A thread waits on an object’s monitor by calling one of the wait methods.

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; 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:

By executing a synchronized instance method of that object.

By executing the body of a synchronized statement that synchronizes on the object.

For objects of type Class, by executing a synchronized static method of that class.

Only one thread at a time can own an object’s monitor.

例子同上。

3.Thread#interrupt

线程对象实例方法(对应的是类方法)
不太准确
的说法是
当前线程中断目标线程(就是interrupt所属的对象/线程),更确切地说是Posts an interrupt request to this Thread


. The behavior depends on the state of this Thread:具体行为分几种情况

Threads blocked in one of Object’s wait() methods or one of Thread’s join() or sleep() methods will be woken up, their interrupt status will be cleared, and they receive an InterruptedException.

如果Thread是因为先前调用Object#
wait
或者Thread#
sleep
/Thread#
join
被阻塞的(这些方法本身是包含编译时异常的),那么调用此方法放之后被中断的线程将收到异常信息(InterruptedException),
中断信息(状态)被清除


Threads blocked in an I/O operation of an InterruptibleChannel will have their interrupt status set and receive an ClosedByInterruptException. Also, the channel will be closed.

如果是因为可中断的IO操作而阻塞,那么调用之后Thread将收到interrupt status(
与上面不同,中断状态还在
),同时收到ClosedByInterruptException,并且关闭IO Channel

If this thread is blocked in a java.nio.channels.Selector then the thread’s interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector’s java.nio.channels.Selector#wakeup wakeup

如果是因为Selector阻塞而被中断,那么立即返回(收到非0值,类似于wakeup调用),Thread将收到interrupt status。

If none of the previous conditions hold then this thread’s interrupt status will be set. Interrupting a thread that is not alive need not have any effect.

其他情形只是会设置线程的中断状态,不会有其他操作
。中断一个死亡的(not alive)的线程没有任何影响。

4.Thread#join

让调用线程目标线程(join所属的thread对象代表的线程)死亡:要么目标线程死亡就立即返回,否则最多等待millis(不管目标线程是否死亡)。如果等待中途有其他线程中断了当前调用线程,那么InterruptedException抛出(查看上面的interrupt)。以下是join方法:

public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;

if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}

if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}


可以发现,join也是基于wait。问题是,wait等待,谁来唤醒它?查看Thread源码,也没看notify或者notifyAll的影子,后来查看(/article/2608626.html):

static void ensure_join(JavaThread* thread) {
Handle threadObj(thread, thread->threadObj());
assert(threadObj.not_null(), "java thread object must exist");
ObjectLocker lock(threadObj, thread);
thread->clear_pending_exception();
java_lang_Thread::set_stillborn(threadObj());
java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
java_lang_Thread::set_thread(threadObj(), NULL);
lock.notify_all(thread);
thread->clear_pending_exception();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: