本章主要对Java中Thread类的基本方法进行学习。
1.序言
Thread类作为线程的基类,提供了一系列方法,主要有:
- Thread.sleep(long):强制线程睡眠一段时间。
- Thread.activeCount():获取当前程序中存活的线程数。
- thread.start():启动一个线程。
- Thread.currentThread():获取当前正在运行的线程。
- thread.getThreadGroup():获取线程所在线程组。
- thread.getName():获取线程的名字。
- thread.getPriority():获取线程的优先级。
- thread.setName(name):设置线程的名字。
- thread.setPriority(priority):设置线程的优先级。
- thread.isAlive():判断线程是否还存活着。
- thread.isDaemon():判断线程是否是守护线程。
- thread.setDaemon(true):将指定线程设置为守护线程。
- thread.join():在当前线程中加入指定线程,使得当前线程必须等待指定线程运行结束之后,才能结束。可以理解成
线程插队
、等待该线程终止
。 - thread.yield():使得当前线程退让出CPU资源,把CPU调度机会分配给同样线程优先级的线程。
- thread.interrupt():使得指定线程中断阻塞状态,并将阻塞标志位置为true。
- object.wai()、object.notify()、object.notifyAll():Object类提供的线程等待和线程唤醒方法。
为了便于阅读,将以上所有方法,放在5篇文章中进行学习。
本章主要学习绿色字体标记的方法。
1.Thread方法学习
1.1.线程休眠
Thread.sleep(long):强制线程睡眠一段时间,其中long的单位为毫秒。
线程休眠:休眠的时间可以用于让其他线程完成当前工作,亦可以减少CPU占用时间,但是不会释放锁持有的锁。可以理解成坐在座位上发呆。
示例代码:
//通过Thread.sleep(ms),指定当前线程进行休眠(但是并没有释放锁)
LOGGER.info("通过Thread.sleep(ms),指定当前线程进行休眠(但是并没有释放锁)");
LOGGER.info("现在时间:" + System.currentTimeMillis() + ",main线程即将休眠1000ms.");
Thread.sleep(1000);
LOGGER.info("休眠结束:" + System.currentTimeMillis() + "\n");
运行结果:
2018-03-12 11:46:06 INFO ThreadBasicDemo:20 - 通过Thread.sleep(ms),指定当前线程进行休眠(但是并没有释放锁)
2018-03-12 11:46:06 INFO ThreadBasicDemo:21 - 现在时间:1520826366873,main线程即将休眠1000ms.
2018-03-12 11:46:07 INFO ThreadBasicDemo:23 - 休眠结束:1520826367873
1.2.线程启动与存活线程数
Thread.activeCount():获取当前程序中存活的线程数。
thread.start():启动一个线程。
示例代码:
//通过Thread.activeCount(),获取程序活着的线程数。
LOGGER.info("通过Thread.activeCount(),获取程序活着的线程数");
LOGGER.info("当前程序活着的线程数:" + Thread.activeCount() + ",一个是main线程,一个是GC线程。");
//添加一个线程
new Thread(() -> {
try {
Thread.sleep(10);//存活10毫秒,方便后续代码能够统计到此线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
LOGGER.info("添加一个匿名线程之后,活着的线程数:" + Thread.activeCount());
Thread.sleep(15);//等着内部匿名线程死掉
LOGGER.info("匿名线程死掉之后,活着的线程数:" + Thread.activeCount() + "\n");
运行结果:
2018-03-12 11:46:07 INFO ThreadBasicDemo:26 - 通过Thread.activeCount(),获取程序活着的线程数
2018-03-12 11:46:07 INFO ThreadBasicDemo:27 - 当前程序活着的线程数:2,一个是main线程,一个是GC线程。
2018-03-12 11:46:07 INFO ThreadBasicDemo:36 - 添加一个匿名线程之后,活着的线程数:3
2018-03-12 11:46:07 INFO ThreadBasicDemo:38 - 匿名线程死掉之后,活着的线程数:2
关于Thread.sleep(long)在后续章节中还会继续学习。
1.3.当前线程、线程组、线程名、优先级、线程存活
Thread.currentThread():获取当前正在运行的线程。
thread.getThreadGroup():获取线程所在线程组。
thread.getName():获取线程的名字。
thread.getPriority():获取线程的优先级。
thread.setName(name):设置线程的名字。
thread.setPriority(priority):设置线程的优先级。
thread.isAlive():判断线程是否还存活着。
示例代码:
new Thread(() -> {
//通过Thread.currentThread()获取当前线程
LOGGER.info("通过Thread.currentThread()获取当前线程");
Thread currentThread = Thread.currentThread();
LOGGER.info("当前线程:" + currentThread);
LOGGER.info("当前线程-名字(thread.getName()):" + currentThread.getName());
LOGGER.info("当前线程-优先级(thread.getPriority()):" + currentThread.getPriority());
LOGGER.info("当前线程-线程组名字:" + currentThread.getThreadGroup().getName() + "\n");
//通过thread.setName(name)设置线程名
LOGGER.info("通过thread.setName(name)设置线程名");
currentThread.setName("张三");
//通过thread.setPriority(priority)设置优先级
LOGGER.info("通过thread.setPriority(priority)设置优先级");
currentThread.setPriority(Thread.MAX_PRIORITY);
LOGGER.info("修改名字和优先级之后:" + currentThread);
//通过thread.isAlive()判断当前线程是否还活着
LOGGER.info("通过thread.isAlive()判断当前线程是否还活着:" + currentThread.isAlive() + "\n");
}).start();
运行结果:
2018-03-12 11:46:07 INFO ThreadBasicDemo:42 - 通过Thread.currentThread()获取当前线程
2018-03-12 11:46:07 INFO ThreadBasicDemo:44 - 当前线程:Thread[Thread-1,5,main]
2018-03-12 11:46:07 INFO ThreadBasicDemo:45 - 当前线程-名字(thread.getName()):Thread-1
2018-03-12 11:46:07 INFO ThreadBasicDemo:46 - 当前线程-优先级(thread.getPriority()):5
2018-03-12 11:46:07 INFO ThreadBasicDemo:47 - 当前线程-线程组名字:main
2018-03-12 11:46:07 INFO ThreadBasicDemo:50 - 通过thread.setName(name)设置线程名
2018-03-12 11:46:07 INFO ThreadBasicDemo:53 - 通过thread.setPriority(priority)设置优先级
2018-03-12 11:46:07 INFO ThreadBasicDemo:55 - 修改名字和优先级之后:Thread[张三,10,main]
2018-03-12 11:46:07 INFO ThreadBasicDemo:58 - 通过thread.isAlive()判断当前线程是否还活着:true
说明:
- 关于线程的字符串描述Thread[Thread-1,5,main],三个值分别代表:线程名、优先级和线程组名。
关于线程优先级在后续章节中还会继续学习。
1.4.守护线程的判断与设置
thread.isDaemon():判断线程是否是守护线程。
thread.setDaemon(true):将指定线程设置为守护线程。
守护线程:也可以称之为后台线程、非用户线程,即随系统结束而结束的线程。
更容易理解的说法:当前程序中,只剩下main线程和守护线程,且main线程执行完毕时,则系统结束。
与用户线程的区别:例如一个线程中通过while(true)无限等待。如果是用户线程,那么这个程序永远都不会关闭;如果是守护线程,那么当其他的用户线程执行完毕之后,程序及会关闭。
示例代码:
LOGGER.info("所谓[守护线程],可以理解为后台线程或非用户线程。");
LOGGER.info("当前程序中,只剩下main线程和守护线程,且main线程执行完毕时,系统结束。");
//守护线程
Thread normalThread = new Thread(() -> {
try {
while (true) {
Thread.sleep(1000);
LOGGER.info("normalThread线程正在工作...");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread daemonThread = new Thread(() -> {
try {
while (true) {
Thread.sleep(1000);
LOGGER.info("daemonThread线程正在工作...");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
LOGGER.info("通过thread.isDaemon()判断当前线程[normalThread]是否是守护线程:" + normalThread.isDaemon());
LOGGER.info("通过thread.isDaemon()判断当前线程[daemonThread]是否是守护线程:" + daemonThread.isDaemon());
LOGGER.info("通过thread.setDaemon(true)将指定线程设置为守护线程,随main线程结束而结束。");
daemonThread.setDaemon(true);
LOGGER.info("通过thread.isDaemon()判断当前线程[daemonThread]是否是守护线程:" + daemonThread.isDaemon());
if (false) {
normalThread.start();
} else {
daemonThread.start();
}
Thread.sleep(2000);//等待线程死掉
LOGGER.info("normalThread是否存活:" + normalThread.isAlive());
LOGGER.info("daemonThread是否存活:" + daemonThread.isAlive());
运行结果:
2018-03-12 11:46:08 INFO ThreadBasicDemo:62 - 所谓[守护线程],可以理解为后台线程或非用户线程。
2018-03-12 11:46:08 INFO ThreadBasicDemo:63 - 当前程序中,只剩下main线程和守护线程,且main线程执行完毕时,系统结束。
2018-03-12 11:46:08 INFO ThreadBasicDemo:85 - 通过thread.isDaemon()判断当前线程[normalThread]是否是守护线程:false
2018-03-12 11:46:08 INFO ThreadBasicDemo:86 - 通过thread.isDaemon()判断当前线程[daemonThread]是否是守护线程:false
2018-03-12 11:46:08 INFO ThreadBasicDemo:87 - 通过thread.setDaemon(true)将指定线程设置为守护线程,随main线程结束而结束。
2018-03-12 11:46:08 INFO ThreadBasicDemo:89 - 通过thread.isDaemon()判断当前线程[daemonThread]是否是守护线程:true
2018-03-12 11:46:09 INFO ThreadBasicDemo:79 - daemonThread线程正在工作...
2018-03-12 11:46:10 INFO ThreadBasicDemo:79 - daemonThread线程正在工作...
2018-03-12 11:46:10 INFO ThreadBasicDemo:97 - normalThread是否存活:false
2018-03-12 11:46:10 INFO ThreadBasicDemo:98 - daemonThread是否存活:true