这里有新鲜出炉的 Java 设计模式,程序狗速度看过来!
Java 程序设计语言
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台(即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se))的总称.
这篇文章主要介绍了 Java 中线程的基本方法使用技巧, 需要的朋友可以参考下
java 中线程的基本方法的熟练使用是精通多线程编程的必经之路,线程相关的基本方法有 wait,notify,notifyAll,sleep,join,yield 等,本文浅要的介绍一下它们的使用方式.
线程的状态图
java 将操作系统中的就绪和运行两种状态统称为可运行状态,java 中线程的状态可以认为有以上六种.
wait
调用该方法的线程进入 WAITING 状态,只有等待另外线程的通知或被中断才会返回,需要注意的是调用 wait() 方法后,会释放对象的锁.
因此,wait 方法一般用在同步方法或同步代码块中.
sleep
sleep 导致当前线程休眠,与 wait 方法不同的是 sleep 不会释放当前占有的锁, sleep(long) 会导致线程进入 TIMED-WATING 状态,而 wait() 方法会导致当前线程进入 WATING 状态
yield
yield 会使当前线程让出 CPU 执行时间片,与其他线程一起重新竞争 CPU 时间片.一般情况下,优先级高的线程有更大的可能性成功竞争得到 CPU 时间片,但这又不是绝对的,有的操作系统对线程优先级并不敏感.
interrupt
中断一个线程,其本意是给这个线程一个通知信号,会影响这个线程内部的一个中断标识位.这个线程本身并不会因此而改变状态 (如阻塞,终止等).
1. 调用 interrupt() 方法并不会中断一个正在运行的线程.也就是说处于 Running 状态的线程并不会因为被中断而被终止,仅仅改变了内部维护的中断标识位而已.
2. 若调用 sleep() 而使线程处于 TIMED-WATING 状态,这时调用 interrupt() 方法,会抛出 InterruptedException, 从而使线程提前结束 TIMED-WATING 状态.
3. 许多声明抛出 InterruptedException 的方法 (如 Thread.sleep(long mills 方法)),抛出异常前,都会清除中断标识位,所以抛出异常后,调用 isInterrupted() 方法将会返回 false.
4. 中断状态是线程固有的一个标识位,可以通过此标识位安全的终止线程.比如, 你想终止一个线程 thread 的时候,可以调用 thread.interrupt() 方法,在线程的 run 方法内部可以根据 thread.isInterrupted() 的值来优雅的终止线程.当然,你可以在线程内部自己维护一个 boolean 变量来控制线程的运行和终止.
现在,我们看一下源码里这个方法是怎么说明的.
/**
* Interrupts this thread.
* 中断这个线程
*
* <p> Unless the current thread is interrupting itself, which is
* always permitted, the {@link #checkAccess() checkAccess} method
* of this thread is invoked, which may cause a {@link
* SecurityException} to be thrown.
* 如果不是当前线程中断自身,这经常是被允许的.不过要检查安全性,
* 可能会抛出安全异常的.
*
* <p> If this thread is blocked in an invocation of the {@link
* Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
* Object#wait(long, int) wait(long, int)} methods of the {@link Object}
* class, or of the {@link #join()}, {@link #join(long)}, {@link
* #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
* methods of this class, then its interrupt status will be cleared and it
* will receive an {@link InterruptedException}.
* 如果中断的线程由于调用一个Object对象的多个wait方法或者当前对象的
* join,sleep方法而正处于阻塞状态(仅表示没有获得CPU的时间片执行,不表示
* 线程的BLOCKED状态).那么它的中断状态将被清除(复位),而且它会收到中
* 断异常.
*
* <p> If this thread is blocked in an I/O operation upon an {@link
* java.nio.channels.InterruptibleChannel InterruptibleChannel}
* then the channel will be closed, the thread's interrupt
* status will be set, and the thread will receive a {@link
* java.nio.channels.ClosedByInterruptException}.
*
* <p> If this thread is blocked in a {@link 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 {@link
* java.nio.channels.Selector#wakeup wakeup} method were invoked.
*
* <p> If none of the previous conditions hold then this thread's interrupt
* status will be set. </p>
* 如果上述的条件都没有比中的话,那么这个线程的中断标志位将被设置.
*
* <p> Interrupting a thread that is not alive need not have any effect.
* 中断一个不存活的线程(未启动或已结束)不会有任何影响
*
* @throws SecurityException
* if the current thread cannot modify this thread
*
* @revised 6.0
* @spec JSR-51
*/
public void interrupt() {
//检查当前线程对this线程的安全权限,如果不允许修改,会抛出异常
if (this != Thread.currentThread()) checkAccess();
//加锁同步
synchronized(blockerLock) {
Interruptible b = blocker;
if (b != null) {
interrupt0(); // Just to set the interrupt flag
b.interrupt(this);
return;
}
}
interrupt0(); //设置标识位,本地方法
}
基本很简单,首先检查当前线程对 this 线程的安全权限,如果不允许修改,会抛出异常.随后加锁同步设置中断标识位.尽管方法声明中有详细说明, 但是代码中看不出来,处于 wating 状态的线程被中断后,中断标识会复位.我认为这是靠本地代码 interrupt0 实现的.
join
在线程 A 上下文中执行了线程 B.join() 语句,其含义是线程 B 执行结束后,join() 方法才会返回,线程 A 才可继续执行.
举个例子,如果你创建了 10 个线程,同时调用 start() 方法执行线程,但是你想让它们有序执行,就可以使用 join 来辅助完成.代码如下:
/***
* 此示例中10个线程在执行时,,需要等待前一个线程执行完;
* 比如线程0要等待main线程执行完
* 线程9要等到线程8执行完
*
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
Thread previous = Thread.currentThread();
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(new Dimon(previous), String.valueOf(i));
thread.start();
previous = thread;
}
TimeUnit.SECONDS.sleep(5);
System.out.println(Thread.currentThread().getName() + "terminate");
}
static class Dimon implements Runnable {
private Thread thread;
public Dimon(Thread thread) {
this.thread = thread;
}@Override public void run() {
try {
thread.join();
} catch(Exception e) {}
System.out.println(Thread.currentThread().getName() + ":terminate");
}
}
总结
以上所述是小编给大家介绍的 Java 中线程的基本方法使用技巧,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的.在此也非常感谢大家对 PHPERZ 网站的支持!
来源: http://www.phperz.com/article/18/0118/353511.html