线程和进程的差别和联系
并发编程
提升效率
引入新的问题(线程安全问题,抛出异常稳定性问题)
Java操作线程 Thread类
1.创建线程
1)创建子类,继承 Thread,重写 run,通过 start启动线程
2)创建子类,实现 Runnable,重写 run ,搭配 Thread 的实例,进行 start
通过 Runnable 表示线程要完成的任务
耦合更低
3)创建子类,继承 Thread ,匿名内部类
4)创建子类,实现 Runnable,匿名内部类
5)lambda 表达式
后台线程:线程不阻止进程的结束
前台线程:线程会阻止进程的结束
默认情况下,咱们创建的线程都是前台的
启动线程 start
调用 start 会真正的调用系统中创建线程的 api 线程跑起来之后,就会自动执行到 run
1.调用 start 动作本身是非常快的,一旦执行 start ,代码就会立即向下执行,不会产生任何阻塞等待
public static void main(String[] args) {Thread t = new Thread(() -> {System.out.println("hello thread");});t.start();System.out.println("hello main");
}
当前看到的情况大部分下是 hello main 在前,也可能会有例外
当 start 之后,main 线程和 t 线程,两个执行流,是"并发执行"关系
如果执行完 start 恰好被调度出 cpu (概率性时间),此时,cpu下次先执行 main 还是 t 就不确定了
2.一个线程对象只能 start 一次
设计 java 的大佬,约定 Thread 对象,只能 start 一次,一个 Thread 对象,只能对应到操作系统中的一个线程.如果需要多个线程,可以多创建 Thread 对象
线程,执行了 start 之后,就是就绪状态/阻塞状态,对于 就绪状态/阻塞状态下的线程,不能再次 start
中断一个线程 (中断,也是操作系统中的一个"专业术语")
正常情况下,一个线程,需要把入口方法执行完(需要通过"打断线程"的操作也需要线程本身,代码做出配合),才能使线程结束,有的时候,希望能够让这个线程提前结束(尤其是,线程在sleep 过程中)
1.通过变量
private static boolean flag = true;
while (flag){{
直接使用线程内置的标志位 isInterruptted()
Thread 对象中,包含一个 boolean 变量,如果为了 false,说明没有人去尝试终止这个线程;如果为 true 说明有人终止这个线程
currentThread 也是 Thread 类提供的一个静态方法.哪个线程调用这个方法,就返回哪个线程对象的引用
while (!Thread.currentThread().isInterrupted()) {System.out.println("hellow thread");try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}
}
线程终止这里,有一个比较奇怪的设定
如果 t 线程正在 sleep,此时 main 中调用 Interrupt方法,就能把 sleep 提前唤醒
(InterruptedException) 支持 sleep 提前唤醒,通过异常,区分 sleep 是达到时间才唤醒的还是提前唤醒
sleep 提前唤醒,触发异常之后,然后 sleep就会把 isInterrupted 标志位,给重置为 false
上述奇怪的设定,主要是为了给程序员更多的操作空间,还没到时间就被唤醒,是否可能存在一些"还没做完的工作"呢?让程序员,自己决定,线程 t 是要继续执行,还是立即结束,还是稍等一会再结束
while (!Thread.currentThread().isInterrupted()) {System.out.println("hellow thread");try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();//相当于是完全忽视了终止请求}
}
while (!Thread.currentThread().isInterrupted()) {System.out.println("hellow thread");try {Thread.sleep(10000);} catch (InterruptedException e) {//e.printStackTrace();//添加 break 之后,此时触发异常的时候就会结束循环,让线程结束.break;}
}
也可再 break 之前添加一些其他的处理逻辑,就相当于是"稍后再结束"
上述的几种方式,本质上,都是 让线程 t 自己,决定自己是否要终止,相当于 main 只是给 t 提供了一个"提醒","建议" 不是"强制执行的"
实际上,操作系统,提供了强制终止线程操作,但是 Java 中并不推荐
如果采取强制终止的手段,很有可能 t 线程的某个逻辑只执行了一半,就可能会造成一些"脏数据的输出"
比如 t 执行过程中针对数据库进行多次的增删改查操作,结果通过上述的强制终止,导致对数据库修改只进行到了一半
使用 Interrupt 方法的时候
1.t 线程没有进行 sleep 等阻塞操作 ,t 的 isInterrupted()方法返回 true,通过循环条件结束 t 线程
2.t 线程中进行了 sleep 等阻塞操作 t 的 isInterrupted() 还是会返回 true, 但是 sleep 如果是被提前唤醒,抛出 InterruptException 同时也会把 isInterrupted() 的返回结果设为 false,此时就需要手动决定是否要结束线程了