Java中Thread类及常见方法


Thread类时JVM中用来管理线程的一个类,也就是指每个线程都有一个唯一的Thread对象与之对应和关联。
Thread类的对象是用来描述一个线程执行流的,JVM会将这些Thread对象组织起来,用于线程的管理和调度。

1. Thread的常见构造方法

Thread类的常见构造方法

2. Thread的常见属性

Thread类的常见属性

  • ID是线程的唯一标识,不同的线程ID不会重复,并且不一定是从1开始分配ID。
  • 名称是线程的名字,一般用在调试时,并且可以更改,且可重复。
  • 状态表示线程当前所处的的一个情况。
  • 优先级高度额线程理论上来说更容易被调度到(要看实际的线程调度策略)。
  • 有关于后台线程,需要知道:JVM会在一个线程的所有非后台线程结束后,才会结束运行。
  • 是否存活,也就是指线程 的run方法是否运行结束。
  • 线程的中断回合线程的状态有一定的关系,一般是指线程在运行时,是否会被暂停运行。可自行设置,但对于JVM而言,仅仅为建议,具体情况还是得看JVM。

3. 启动线程

在之前的代码中,我们已经可以通过覆写run方法来创建一个线程,但线程对象被创建出来并不意味这线程就开始运行了。
因为我们覆写的run方法,只是告诉线程要做的事情的指令清单,但使用start方法,线程才会真正地去独立执行。
调用start方法,才真的在操作系统的底层创建出了一个线程。

4. 中断线程

在实际的执行流中,一个线程不一定会完全一直执行已经规定好了的步骤,可能在中途会有一些特殊的要求,于是需要增加一些机制,让线程暂时停止,先去干其他的事情,等其他的事情干完之后,再去接着做之前还未做完的事情。
目前常见的中断线程的方法有两种:

  1. 通过共享的标记来进行沟通。
  2. 调用interrupt方法来通知。

4.1. 通过共享的标记来进行沟通

需要非标志为加上volatile关键字。

public class ThreadDemo {
	private static class MyRunnable implements Runnable {
		public volatile boolean isQuit = false;
		
		@Override
		public void run() {
			while (!isQuit) {
				System.out.println(Thread.currentThread().getName() + ": 别管我,我忙着转账呢!");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			System.out.println(Thread.currentThread().getName() + ": 啊!险些误了大事");
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		MyRunnable target = new MyRunnable();
		Thread thread = new Thread(target, "李四");
		System.out.println(Thread.currentThread().getName() + ": 让李四开始转账。");
		thread.start();
		Thread.sleep(10 * 1000);
		System.out.println(Thread.currentThread().getName() + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
		target.isQuit = true;
	}
}

4.2. 调用interrupt方法来通知

interrupted方法
interrupt可以让需要停止的线程看到停止信号后,可以主动把手上的工作做到一个阶段完成,然后再主动退出。
但实际上interrupt仅仅是发了个消息(给需要停止的线程设置了一个停止标志),实际上并不会影响线程的运行。
但若线程处于休眠状态时(比如sleep、join),意味着线程无法立即执行停止操作,则需要JVM以异常的形式,来通知线程。

public class ThreadDemo {
	private static class MyRunnable implements Runnable {
		@Override
		public void run() {
			// 两种方法均可以
			while (!Thread.interrupted()) {
			//while (!Thread.currentThread().isInterrupted()) {
				System.out.println(Thread.currentThread().getName() + ": 别管我,我忙着转账呢!");
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
					System.out.println(Thread.currentThread().getName() + ": 有内鬼,终止交易!");
					// 注意此处的 break
					break;
				}
			}
			System.out.println(Thread.currentThread().getName() + ": 啊!险些误了大事");
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		MyRunnable target = new MyRunnable();
		Thread thread = new Thread(target, "李四");
		System.out.println(Thread.currentThread().getName() + ": 让李四开始转账。");
		thread.start(); Thread.sleep(10 * 1000);
		System.out.println(Thread.currentThread().getName() + ": 老板来电话了,得赶紧通知李四对方是个骗子!");
		thread.interrupt();
	}
}

thread对象收到通知的方式有两种:

  1. 如果线程是因为调用 wait / join / sleep 等方法二阻塞挂起,则会以 InterruptedException 异常的形式通知,并且清除中断标志。
  2. 否则就只是内部的一个中断标志被设置,thread对象可以通过,可以通过 Thread.interrupted() 或者 Thread.currentThread().isInterrupted() 来判断线程的中断标志是否被设置。这种方式的通知会更加及时,即使线程正在sleep状态也可以马上收到。

5. 等待线程

在例如使用IO时,我们会需要等待线程完成它的工作后,才能进行值的下一步的工作于是会使用到线程的等待。
join方法

public class ThreadDemo {
	public static void main(String[] args) throws InterruptedException {
		Runnable target = () -> {
			for (int i = 0; i < 10; i++) {
				try {
					System.out.println(Thread.currentThread().getName() + ": 我还在工作!");
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			System.out.println(Thread.currentThread().getName() + ": 我结束了!");
		};
		
		Thread thread1 = new Thread(target, "李四");
		Thread thread2 = new Thread(target, "王五");
		System.out.println("先让李四开始工作");
		thread1.start();
		thread1.join();
		System.out.println("李四工作结束了,让王五开始工作");
		thread2.start();
		thread2.join();
		System.out.println("王五工作结束了");
	}
}

6. 获取线程引用

获取当前线程引用

public class ThreadDemo {
	public static void main(String[] args) {
		Thread thread = Thread.currentThread();
		System.out.println(thread.getName());
	}
}

7. 休眠线程

虽然我们可以使用sleep来控制线程休眠,但因为线程的调度是不可控的,所以这个方法只能保证实际休眠时间大于等于参数设置的休眠时间。
线程休眠

public class ThreadDemo {
	public static void main(String[] args) throws InterruptedException {
		System.out.println(System.currentTimeMillis());
		Thread.sleep(3 * 1000);
		System.out.println(System.currentTimeMillis());
	}
}

8. 线程让出资源

Thread类中的yield方法,可以让出一部分资源,其中主要指CPU资源,让线程从运行状态,转换为就绪状态,并且随时可以继续被调度回CPU。
yield方法主要用于执行一些耗时较长的计算任务时,为了防止计算机处于“卡顿”的线程,会时不时的让出一些CPU的资源,给操作系统内的其他进程使用。
表现为CPU主要由其他线程使用,而使用yield的线程使用CPU的机会会很少。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值