本就无大事,庸人觅闲愁.
文章目录
- 1. 线程创建
- 2. 线程中断
- 2.1 通知终止后立即终止
- 2.2 通知终止,通知之后线程继续执行
- 2.3 通知终止后,添加操作后终止
- 3. 线程等待
- 4. 线程休眠
- 5. 获取线程实例
1. 线程创建
创建线程有五个方法
详情见我的另一个文章
https://editor.csdn.net/md/?articleId=128293107
分别是继承Thread,实现Runnable接口,使用匿名内部类继承Thread,使用匿名内部类,实现Runnale接口,使用Lambda表达式.
2. 线程中断
线程中断是t通过标志位通知线程快要终止了,线程接收到信号后,可以加入自己的操作,做出不同反应.
2.1 通知终止后立即终止
如下代码
public class InterruptedThread {
public static void main(String[] args)throws InterruptedException {
Thread t = new Thread(()->{
while (!Thread.currentThread().isInterrupted()) {
System.out.println("hello thread");
break;
}
});
t.start();
t.sleep(1000);
t.interrupt();
}
}
说明:
1.Thread.currentThread()的作用是获取当前的进程
2.isInterrupted()源码如下
线程调用这个函数,获取标志位,也就是true或者false
返回值是false时,通知这个线程未被终止,while()循环继续.
返回值是true时,通知线程即将被终止.是否选择终止,取决于线程之后的操作.
3.t.interrupt(),将标志位改为true,在上述代码中,线程标志位为true时,while循环结束,无其他操作,线程立刻终止.
执行结果
2.2 通知终止,通知之后线程继续执行
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while (!Thread.currentThread().isInterrupted()) {
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
t.sleep(1000);
t.interrupt();
}
结果如下图
说明:
调用t.interrupt();将标志位改为true,如果线程正在sleep,interrupt()会触发sleep内部的异常,导致sleep提前返回,将标志位重新改为false,唤醒进程.
所以,在提醒终止后,线程未选择终止,而是继续执行
2.3 通知终止后,添加操作后终止
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(()->{
while (!Thread.currentThread().isInterrupted()) {
System.out.println("hello thread");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
try {
System.out.println("我是添加的操作");
System.out.println("1 + 1 = 2");
Thread.sleep(500);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
break;
}
}
});
t.start();
t.sleep(1000);
t.interrupt();
}
结果如下图
说明:
t.interrupt(),将标志位改为true,但线程正在sleep,触发catch异常,之后try-catch捕获异常,可以在try中添加操作,之后break,直接跳出循环.
3. 线程等待
线程抢占式执行,随机调度,线程执行的顺序由操作系统操控,不可预知.
线程等待,目的是控制两个线程结束的顺序.
若是在t2中调用t1.join(),意味着t2会等待t1结束后才会终止自身进程.
public static void main(String[] args) {
System.out.println("main开始喽");
Thread t = new Thread(()->{
for(int i = 0; i < 3; i++){
System.out.println("hello thread");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main结束喽");
}
t.join();执行此代码时,main()函数会等待t线程结束后,再结束自身调度.
4. 线程休眠
操作系统每次只会在就绪序列中选择合适线程执行.
调用sleep()函数,使线程从就绪序列置到阻塞序列
由于线程调度有时间开销,线程休眠结束后,线程唤醒之后不会立即被执行.
5. 获取线程实例
1.使用线程调度两个线程
public static void concurrency() {
// 使用两个线程分别完成自增.
Thread t1 = new Thread(() -> {
long a = 0;
for(long i = 0; i < 100_0000_0000L; i++) {
a++;
}
});
Thread t2 = new Thread(() -> {
long b = 0;
for(long i = 0; i < 100_0000_0000L; i++) {
b++;
}
});
// 开始计时
long beg = System.currentTimeMillis();
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 结束计时
long end = System.currentTimeMillis();
System.out.println("并发执行时间: " + (end - beg) + " ms");
}
2.正常调度两个线程
public static void serial() {
// 为了衡量带没带的执行速度, 加上个计时的操作
// currentTimeMillis 获取到当前系统的 ms 级时间戳.
long beg = System.currentTimeMillis();
long a = 0;
for (long i = 0; i < 100_0000_0000L; i++) {
a++;
}
long b = 0;
for (long i = 0; i < 100_0000_0000L; i++) {
b++;
}
long end = System.currentTimeMillis();
System.out.println("执行时间: " + (end - beg) + " ms");
}
时间对比,会发现使用线程之后,大大减小时间开销.