浅尝辄止之线程基础


  • 线程创建

  • 了解
  1. 继承Thread类,覆盖run()方法;(创建线程方法1)
  2. 实现Runnable接口,并传递该实现类对象作为Thread对象的构造函数参数(创建线程方法2)
  3. 每个java程序至少存在一个线程(主线程);
  4. 只有调用线程对象的start()方法才真正启动了线程;
  5. 当所有非后台线程执行结束(或者某个线程调用System.exit())时,该程序执行完毕。



  • 线程中断

  • 了解
  1. java提供中断机制来通知线程表明我们想结束执行(线程设置中断标识),但需要线程检查是否被中断,线程也可以决定对中断请求的处理方式,即可忽略中断请求继续执行。(好比女友让你别老玩游戏,但是是否继续玩游戏,玩得程度完全取决于你)
  2. Thread相关接口

void interrupt()

设置线程的中断状态

boolean isInterrupted()

检测是否中断状态

static boolean interrupted()

检测是否中断状态,并清除中断状态






	public static void main(String[] args) {
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				while (true) {
					System.out.println("游戏中...请勿扰");
					if (Thread.currentThread().isInterrupted()) {
						System.out.println("女友:别玩游戏了");
						// ------------------1.继续玩 ------------------
						// System.out.println("我:没有理会继续玩");
						// ------------------1.继续玩 ------------------
						// ------------------2.好吧,马上关机 ------------------
						// System.out.println("我:好吧,马上关机!睡觉!");
						// break;
						// ------------------2.好吧,马上关机 ------------------
						// ------------------3.在玩一会儿 ------------------
						System.out.println("我:等等,再玩一会儿就赢了!");
						try {
							TimeUnit.SECONDS.sleep(1);
							System.out.println("Game Over!");
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						break;
						// ------------------3.再玩一会儿 ------------------
						// ------------------4.跪键盘中 ------------------
						// System.out.println("(我)跪键盘中...");
						// break;
						// ------------------4.跪键盘中 ------------------
					}
				}
			}
		});
		// 开始玩游戏
		t.start();
		try {
			// 刚开始玩
			TimeUnit.SECONDS.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		// 女友走过来,让我别玩了,并且罚我跪键盘(实质:设置线程的中断标识)
		t.interrupt();

	}
上面代码,线程中断后可以有多种响应。检测到中断是不理会继续执行任务?马上退出当前执行任务?sleep后退出?又或者是sleep后继续执行?这就需要与中断请求方协商好,视实际情况而定。当执行第3种相应时,会抛出异常:“java.lang.InterruptedException: sleep interrupted ”。因为Thread.sleep、Thread.join、Object.wait、LockSupport.park等阻塞接口在检查到线程的中断状态时,会抛出InterruptedException,同时会清除线程的中断状态


  • 线程Join

  • 了解

  1. thread的join(),可暂停执行调用线程,直到被调用线程执行完毕。
	public static void main(String[] args) {
		Thread t1 = new Thread(new Runnable() {

			@Override
			public void run() {
				System.out.println("---我是分支线程1beg---");
				try {
					TimeUnit.SECONDS.sleep(3);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("---我是分支线程1end---");
			}
		});

		Thread t2 = new Thread(new Runnable() {

			@Override
			public void run() {
				System.out.println("---我是分支线程2beg---");
				try {
					TimeUnit.SECONDS.sleep(2);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("---我是分支线程2end---");
			}
		});

		t1.start();
		t2.start();

		try {
			System.out.println("主线程1");
			t1.join();
			// t1.join(1000);
			// t1.join(1000,10000);
			System.out.println("主线程2");
			t2.join();
			System.out.println("主线程3");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
上面代码,主线程调用了t1.join()、t2.join(),那么主线程会在等待t1、t2线程均执行完毕才会执行System.out.println("主线程3");其中注释的t1.join(1000)\t1.join(1000,10000)会在等待若干毫秒\毫秒+纳秒后继续执行下面代码。


  • 线程组创建

  • 了解

  1. 每一个线程归属于某个线程组管理,main()中创建的线程归属线程组main,也可以创建线程时可以明确指定线程组
  2. 可中断线程组下及其子线程组下所有线程,即该组下的子孙线程都调用interrupt()
	public static void main(String[] args) {

		// 每一个线程归属于某个线程组管理,main()中创建的线程归属线程组main
		Thread oneT = new Thread(new SleepTask(), "testMain");
		ThreadGroup mainGroup = oneT.getThreadGroup();
		System.out.println("main函数创建的线程归属线程组:" + mainGroup.getName());

		// 创建一线程组
		ThreadGroup group = new ThreadGroup("testGroup");
		int size = 5;
		for (int i = 0; i < size; i++) {
			// 创建线程时明确指定的线程组
			Thread t = new Thread(group, new SleepTask());
			t.start();
		}

		int num = group.activeCount();
		Thread[] threads = new Thread[num];
		// 获取线程组testGroup下活跃的线程
		group.enumerate(threads);

		// 统一归属线程组:testGroup
		for (Thread t : threads) {
			System.out.println(t.getName() + "归属线程组:" + t.getThreadGroup().getName());
		}
		// 中断线程组testGroup下及其子线程组下所有线程,即该组下的子孙线程都调用interrupt()
		group.interrupt();
	}

	static class SleepTask implements Runnable {
		@Override
		public void run() {
			try {
				System.out.println(Thread.currentThread().getName() + "-beg");
				TimeUnit.SECONDS.sleep(new Random().nextInt(8));
				System.out.println(Thread.currentThread().getName() + "-end");
			} catch (InterruptedException e) {
				System.out.println(Thread.currentThread().getName() + "-" + e.getMessage());
			}

		}
	}

  • 线程(组)异常处理

  • 了解

  1. run() 方法不接受 throws 子句
    • 当运行时异常被抛出,默认的行为是在控制台写下stack trace并结束任务(可自定义设置未捕获到异常处理程序);
    • 当非运行时异常被抛出,必须捕捉并处理。
  2. 未捕获到异常处理程序顺序
    1. 线程对象通过setUncaughtExceptionHandler()设置的未捕获异常处理程序(不存在查找2)
    2. 线程对象所归属的线程组对象(重写ThreadGroup uncaughtException())设置的未捕获异常处理程序(不存在查找3)
    3. 通过Thread.setDefaultUncaughtExceptionHandler()设置的默认未捕获异常处理程序(不存在查找4)
    4. 未捕获异常的stack trace写入操控台并结束任务
  3. Thread相关接口

void setUncaughtExceptionHandler

设置该线程由于未捕获到异常而突然终止时调用的处理程序

static void setDefaultUncaughtExceptionHandler

设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。









public class ThreadUncheckedException {

	public static void main(String[] args) {
		
		//设置默认未捕获异常处理程序
		Thread.setDefaultUncaughtExceptionHandler(new CustomDefaultUncaughtHandler());
		
		MyThreadGroup threadGroup = new MyThreadGroup("myGroup");
		Thread t = new Thread(threadGroup,new SleepTask());
		
		//设置线程对象的未捕获异常处理程序
		t.setUncaughtExceptionHandler(new CustomThreadUncaughtHandler());
		t.start();
	}

	private static class MyThreadGroup extends ThreadGroup {

		public MyThreadGroup(String name) {
			super(name);
		}

		@Override
		//设置线程组对象的未捕获异常处理程序
		public void uncaughtException(Thread t, Throwable e) {
			// e.printStackTrace();
			System.out.printf("[线程组]异常处理程序:已处理线程%s异常 [%s:%s]", t.getName(), e.getClass().getName(), e.getMessage());
			// 一子错满盘皆输
			interrupt();
		}

	}

	private static class SleepTask implements Runnable {
		@Override
		public void run() {
			// 当非运行时异常被抛出,必须捕捉并处理
			try {
				TimeUnit.SECONDS.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			// throws NumberFormatException(运行时异常)
			Integer.parseInt("test");

			System.out.println("看到此输出,表明木有异常!");
		}
	}
	
	private static class CustomDefaultUncaughtHandler implements UncaughtExceptionHandler {

		@Override
		public void uncaughtException(Thread t, Throwable e) {
			// e.printStackTrace();
			System.out.printf("[默认线程]异常处理程序:已处理线程%s异常 [%s:%s]", t.getName(), e.getClass().getName(), e.getMessage());
		}
	}

	private static class CustomThreadUncaughtHandler implements UncaughtExceptionHandler {

		@Override
		public void uncaughtException(Thread t, Throwable e) {
			// e.printStackTrace();
			System.out.printf("[线程]异常处理程序:已处理线程%s异常 [%s:%s]", t.getName(), e.getClass().getName(), e.getMessage());
		}
	}
}
可以通过注释相关的未捕获异常处理程序来验证异常处理程序顺序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值