2. Java线程基础
一、 创建新线程
1.1 继承Thread类
Thread t1 = new Thread(); t1.start();
start()方法可以创建一个新的线程,并让这个线程执行run()方法
Thread t2 = new Thread(); t2.run()
这种直接用run() 方法,不会创建一个新的线程,只是在当前线程中串行的执行run方法。
1.2 通过Runnable接口实现
public class CreateThread implements Runnable(){
public static void mian(String args[]){
Thread t1 = new Runnable(new CreateThread());
t1.start();
}
@Override
public void run(){
System.out.println("Runnable Thread");
}
}
二、 线程终止
Thread提供了stop() 方法,但是这是已经被废弃的方法。因为stop()方法会强行将执行一半的线程终结,可能会引
起数据不一致的情况。

所以停止线程的方法,可以定义一个标记变量,用于指示线程是否需要退出。
三、 线程中断
与线程中断有关的三个方法
public void Thread.interrupt() //中断线程 public boolean Thread.isInterrupted() //判断是否被中断 public static boolean Thread.interrupted //判断是否被中断,并清除当前中断状态
Thread.interrupt()方法是一个实例方法。他通知目标线程中断,也就是设置中断标志。中断标志表示当前线程已经被中断了。
Thread.isInterrupted() 方法也是实例方法,它判断当前线程是否有被中断(通过检查中断标志位)。
Thread.interrupted() 也是用来判断当前线程的中断状态,但同时会清楚线程的中断标志位状态。
Thread.sleep()方法会让当前线程休眠若干时间,它会抛出一个InterruptedException 中断异常。 InterruptedException 不是运行时异常,也就是说程序必须捕获并且处理它,当线程在sleep() 休眠时,如果被中断,这个异常就会产生。
public static void main(String args[]) throws InterrupterException{
Thread t1 = new Thread();
@Override
public void run(){
while(true){
if(Thread.currentThread().isInterrupted()){
System.out.println("Interruted");
break;
}
try{
Thread.sleep(2000);
}catch(InterruptedException e){
System.out.println("Interrupted When Sleep");
//设置中断状态
Thread.currentThread().interrupte();
}
Thread.yield();
}
};
t1.start();
Thread.sleep(2000);
t1.interrupt();
}
执行sleep()方法,会抛出异常,被catch捕获。可以立即退出线程了,但是为了保证数据的完整性,我们可以在
catch中重新设置中断状态(sleep()由于线程中断,会清除中断标记状态),继续后续的处理。
四、wait() 和 nodify()
一个线程调用了object.wait() 就进入了等待队列,直到其他线程调用了object.nodify()方法。当
object.nodify()被调用时,会随机从等待队列中选择一个线程,将其唤醒。nodifyAll(),唤醒等待队列中
的所有线程。
Object.wait() 方法不是可以随便调用的。它必须包含在对应的 synchronized 语句中,无论是wait() 或者 notify() 都需要首先获得目标对象的一个 监视器。而wait() 方法执行后,会释放这个监视器。这样能使其他线程不至于因为该线程的休眠而全部无法正常执行

五、挂起(suspend)和继续执行(resume)线程(已被废弃,不推荐使用)
一个线程执行suspend方法是会挂起,但是不释放锁,导致其他线程必须等到resume被执行,才能得到锁。如果
resume在suspend前不幸被执行,可能导致线程被永久挂起。

六、 等待线程join
两个join方法。
public final void join() throws InterruptedException
public final synchronized void join(long millis) throws InterruptedException
第一个join() 方法表示无限等待,它会一直阻塞当前线程,知道目标线程执行完毕((别的线程得等调用了join的线程执行完)。第二个方法给出了一个最大等待时间,如果超过给定时间目标线程还在执行,当前线程也会因为“等不及了”,而继续往下执行。
public class JoinMain{
public volatile static int i = 0;
public static class AddThread extends Thread{
@Override
public void run(){
for(i=0;i<10000000;i++);
}
}
public static void main(String[] args) throws InterruptedException{
AddThread at = new AddThread();
at.start();
at.join();
System.out.println(i);
}
}
如果不使用join(),可能输出的 i 的值很小,因为AddThread() 没来得及全部执行完,就已经输出了。使用了join(),只有等AddThread() 执行完,才执行其他线程。
join方法本质是让调用线程wait() 在当前线程的实例上。
join方法的核心代码:
while(isAlive){
wait(0);
}
七、谦让yield() 方法:
定义如下:
public static native void yield();
调用该方法后,线程会让出CPU,但不意味着不进行CPU的竞争。让出CPU后,还是会进行竞争的。如果认为一
个线程不是那么重要,优先级不是那么高,那么可以适当调用Thread.yield(),让其他线程有更多机会。
八、守护线程Daemon
守护线程是一种特殊的线程,就和它的名字一样,它是系统的守护者,在后台默默地守护一些系统服务,比如垃圾
回收线程,JIT线程就可以理解守护线程。与之对应的就是用户线程,用户线程就可以认为是系统的工作线程,它
会完成整个系统的业务操作。用户线程完全结束后就意味着整个系统的业务任务全部结束了,因此系统就没有对象
需要守护的了,守护线程自然而然就会退。当一个Java应用,只有守护线程的时候,虚拟机就会自然退出。下面以
一个简单的例子来表述Daemon线程的使用。
public class DaemonDemo {
public static void main(String[] args) {
Thread daemonThread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
System.out.println("i am alive");
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("finally block");
}
}
}
});
daemonThread.setDaemon(true);
daemonThread.start();
//确保main线程结束前能给daemonThread能够分到时间片
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出结果为:
i am alive finally block i am alive
上面的例子中daemodThread run方法中是一个while死循环,会一直打印,但是当main线程结束后
daemonThread就会退出所以不会出现死循环的情况。main线程先睡眠800ms保证daemonThread能够拥有一次
时间片的机会,也就是说可以正常执行一次打印“i am alive”操作和一次finally块中"finally block"操作。紧接着
main 线程结束后,daemonThread退出,这个时候只打印了"i am alive"并没有打印finnal块中的。因此,这里需
要注意的是守护线程在退出的时候并不会执行finnaly块中的代码,所以将释放资源等操作不要放在finnaly块中执
行,这种操作是不安全的
线程可以通过setDaemon(true)的方法将线程设置为守护线程。并且需要注意的是设置守护线程要先于start()方
法,否则会报
Exception in thread "main" java.lang.IllegalThreadStateException at java.lang.Thread.setDaemon(Thread.java:1365) at learn.DaemonDemo.main(DaemonDemo.java:19)
这样的异常,但是该线程还是会执行,只不过会当做正常的用户线程执行。
九、线程状态转化图

参考
《实战Java高并发程序设计》
8904

被折叠的 条评论
为什么被折叠?



