线程

-- Start

线程与进程的区别

线程之间可以共享内存, 而每个进程有自己独立的内存空间.


定义线程

继承 Thread

定义线程的一种方式是继承 Thread, 然后覆盖 Thread 类的 run 方法.

public class Test {

	public static void main(String[] args) throws Exception {
		MyThread myThread = new MyThread();
		myThread.start(); // 启动线程
	}
}

class MyThread extends Thread {

	@Override
	public void run() {
		System.out.println("to do my work.");
	}

}

实现 Runnable

定义线程的另一种方式是实现 Runnable, 然后实现 Runnable 的 run 方法.

public class Test {

	public static void main(String[] args) throws Exception {
		MyRun myRun = new MyRun();
		Thread myThread = new Thread(myRun);
		myThread.start(); // 启动线程
	}
}

class MyRun implements Runnable {

	public void run() {
		System.out.println("to do my work.");
	}

}

注意 start 用来启动线程, 而不是 run 方法. 通常我们推荐使用第二种方式来创建线程, 如果我们不打算修改或增强某个类, 我们不应该随便继承一个类.

线程优先级(priority)

每个线程都有一个优先级, 线程调度器在调度线程时会优先选择那些优先级较高的线程. 我们可以通过 getPriority 方法来查看线程的优先级, 我们可以通过 setPriority 方法来设置优先级, 我们可以设置从 Thread.MIN_PRIORITY 到 Thread.MAX_PRIORITY 的任何值(从1-10), 通常我们选择 Thread.NORM_PRIORITY (5).
Thread 的 yield 方法可以让线程暂时放弃运行, 此时线程调度器可以选择其他线程来运行.


守护线程(daemon)

守护线程用来为其他线程提供服务, 所以在一般情况下, 它会常驻在内存中而不会结束, 当只剩下守护进程时, 守护进程就终止了, 因为其他线程都结束了, 它还提供服务给谁呢? 我们可以通过 isDaemon 方法来判断一个线程是否是守护线程, 我们也可以通过 setDaemon 方法来设置一个普通线程为一个守护线程, 不过它必须在线程启动之前调用.


线程状态

通过 Thread 的 getState 方法我们可以得到线程的状态, 枚举类 Thread.State 封装了线程的状态, 线程可以有如下 6 种状态.

  • NEW: 在调用 start 方法之前, 线程处于此状态.
  • RUNNABLE: 线程正在运行或等待线程调度器调度.
  • BLOCKED: 线程等待某个对象的锁.
  • WAITING: 线程等待其他线程唤醒.
  • TIMED_WAITING: 线程等待其他线程唤醒或超时
  • TERMINATED: 线程终止.

中断状态 (interrupted status)

如果我们想停止当前正在运行的线程该怎么办呢? Thread 类有一个 stop 方法用来停止线程, 可惜它已经不推荐使用了, 原因是它强制终止线程, 极有可能会破坏对象.
虽然现在我们无法强制终止一个线程, 但是我们却可以通过 interrupt 方法来请求终止一个线程. 它会设置线程的中断状态标志位, 每个线程都应该时不时的判断该标志位以决定是否终止线程.
如果一个线程由于调用了 wait, join 和 sleep 等方法而被阻塞了, 那么它就没有机会去检查中断状态了, 如果此时我们调用 interrupt 方法来试图终止该线程, 那么 wait, join 和 sleep 等方法会抛出 InterruptedException 异常从而退出阻塞状态.
每个线程可以自己决定如何应对中断请求, 我们可以终止线程, 也可以忽略该中断请求.

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class Test {

	public static void main(String[] args) throws Exception {
		MyRun myRun = new MyRun();
		Thread myThread = new Thread(myRun);
		myThread.start(); // 启动线程

		// 假设该线程从一个很大的文件读取数据
		// 运行一段时间后, 由于某种原因, 我们想停止该线程
		// 设置该线程的中断状态为 true
		myThread.interrupt();
	}
}

class MyRun implements Runnable {

	public void run() {

		try {
			Scanner s = new Scanner(new File("test.txt"));

			// 通过 isInterrupted 方法检查中断状态, 如果中断状态为 true, 则退出循环
			while (Thread.currentThread().isInterrupted() && s.hasNextLine()) {
				String line = s.nextLine();
				System.out.println(line);

				Thread.sleep(3000);
			}
		} catch (InterruptedException e) {
			// 在 sleep 方法运行前或运行中调用 interrupt方法将会抛出此异常来跳出阻塞状态并清除中断状态
			// 我们应该再次设置中断状态
			Thread.currentThread().interrupt();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

	}

}

线程组(ThreadGroup)

正如文件夹用来管理一组相关的文件一样, 线程组用来管理一组相关的线程, 我们可以通过 ThreadGroup 类的构造方法来创建一个线程组,
在创建线程时也可以指定一个线程组. 一旦创建了线程组, 我们就可以利用它提供的方法来对一组线程进行操作, 省去了我们逐个操作的麻烦.


异常处理器

线程的 run 方法不能抛出被检查异常, 但是我们可以给线程指定异常处理器.

设置或获得默认异常处理器

  • getDefaultUncaughtExceptionHandler
  • setDefaultUncaughtExceptionHandler

设置或获得某个线程的异常处理器

  • getUncaughtExceptionHandler
  • setUncaughtExceptionHandler


---更多参见:Java 精萃

-- 声 明:转载请注明出处
-- Last Updated on 2012-06-20
-- Written by ShangBo on 2012-06-20
-- End
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值