app网站开发的特点,商城网站开发业务,wordpress菜单手机显示下拉菜单,网站建设服务8文章目录 Thread 类及常见方法启动一个线程中断一个线程变量型中断调用 interrupt() 方法来通知观察标志位是否被清除 等待一个线程获取当前线程引用休眠当前线程 线程的状态观察线程的所有状态观察 1: 关注 NEW 、 RUNNABLE 、 TERMINATED 状态的切换 多线程带来的风险为什么会… 文章目录 Thread 类及常见方法启动一个线程中断一个线程变量型中断调用 interrupt() 方法来通知观察标志位是否被清除 等待一个线程获取当前线程引用休眠当前线程 线程的状态观察线程的所有状态观察 1: 关注 NEW 、 RUNNABLE 、 TERMINATED 状态的切换 多线程带来的风险为什么会这样 Thread 类及常见方法
Thread类是我java给提供的一个线程类其内部包含了很多帮助我们的方法。除了上次讲述的初始化方法外还有哪些呢请看下面的内容
启动一个线程
我们知道了通过复写run方法创建一个线程对象在我的上一篇文章中说明过但是线程被创建出来并不代表线程已经开始了运行。因此只有调用了start方法才是真正的创建了一个线程用法如下
public class Main {public static void main(String[] args) throws InterruptedException{Thread tnew Thread(()-{while(true){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(我是lambda表达式创建出的线程);}});t.start();while(true){Thread.sleep(1000);System.out.println(Hello world!);}}
}中断一个线程
线程在执行的过程中不仅要知道如何进行启动中断也同样重要因为线程的执行只有当线程这个任务彻底完成后才会中断但是这个机制是不好的因为这时候就会导致一些有问题的线程我们没法立刻进行中断那么现在主要有哪些中断线程的方法呢
变量型中断
使用一个自定义变量进行中断线程请看如下代码
class Mythread extends Thread{public void run(){while(Main.flag){try {sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(正常交易中);}System.out.println(有内鬼停止交易);}
}
public class Main {public static boolean flagtrue;public static void main(String[] args) throws InterruptedException{Thread tnew Mythread();t.start();int cnt0;while(true){Thread.sleep(1000);if(cnt5)System.out.println(令线程正常交易);cnt;if(cnt5){System.out.println(通知线程有内鬼);flagfalse;break;}}}
}请看上面这个代码这个代码很明显就是用了一个flag变量来控制这里面的while循环是否可以继续执行但是这个方法非常的不优雅感觉有种很土的感觉那难道我们的java就没有官方提出来一些方法来使用嘛当然是有的。那就是下面三个方法
调用 interrupt() 方法来通知
方法说明public void interrupt()中断对象关联的线程如果线程正在阻塞则以异常方式通知否则设置标志位public static boolean interrupted()判断当前线程的中断标志位是否设置 调用后清除标志位public boolean isInterrupted判断对象关联线程的标志位是否设置调用后不清除标志位
那么这些方法该怎么使用呢请看如下代码
class Mythread extends Thread{public void run() {while(!Thread.interrupted()){try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(正常交易中);}System.out.println(有内鬼停止交易);}
}
public class Main {public static boolean flagtrue;public static void main(String[] args) throws InterruptedException{Thread tnew Mythread();t.start();int cnt0;while(true){Thread.sleep(1000);if(cnt5)System.out.println(令线程正常交易);cnt;if(cnt5){System.out.println(通知线程有内鬼);t.interrupt();break;}}}
}在这个代码运行截图中我们可以看到即使抛出了异常但是这个代码仍然没有终止那么这是为什么呢因为我们看一下上面的对这些的方法的介绍。interrupted()方法介绍说了调用本方法可以查看此时的标志位并且在查看过后就会清除标志位那么按照这个代码的逻辑我们来看一下。首先我们调用了interrupt方法设置了我们的标记位并且检测到线程此时正在休眠因此我们以异常的形式进行了抛出之后当调用interrupted方法进行判断的时候此时标志位未被设置因此循环将会继续执行那么难道就没有办法了吗当然是有的第一个办法就是将异常抛出因为我们学过当我们将异常抛出的时候那么这个方法就不会继续往后执行了第二个办法就是在循环内部加一个break thread 收到通知的方式有两种
如果线程因为调用 wait/join/sleep 等方法而阻塞挂起则以 InterruptedException 异常的形式通 知清除中断标志 当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择 忽略这个异常, 也可以跳出循环结束线程.否则只是内部的一个中断标志被设置thread 可以通过 Thread.interrupted() 判断当前线程的中断标志被设置清除中断标志 Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置不清除中断标志
观察标志位是否被清除
观察标志位是否被清除我们来讲述一下那两个方法 首先标志位大家可以理解是什么呢其实就是我们第一种方法定义的一个boolean的变量一样那么清除标志位就相当于把这个标志位重新设置成了false那样子设置标志位就相当于将其设置为true那么带着这种理解我们来看一下这两种方法首先是public static boolean interrupted()这个方法就像是一个自动开关一样当你检查的时候相当于把灯打开了当你检查完毕后又把灯给重新随手关上了public boolean isInterrupted而这个则是不会关闭。 等待一个线程
等待一个线程什么是等待一个线程呢其实就是等待一个线程结束我们刚刚说过线程是并发执行的但是有些时候我们希望这个线程是顺序的有时又可以是并发那么该怎么做呢那就需要线程的等待了。顾名思义线程的等待其实就是等待一个线程的任务进行完毕后再去执行接下来的代码因此就实现了线程的顺序执行那么该怎么完成呢那就是用join方法请看下面的代码 class Mythread extends Thread{public void run() {int i0;while(i6){try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();break;}i;System.out.println(正常交易中);}//System.out.println(有内鬼停止交易);}
}
public class Main {public static boolean flagtrue;public static void main(String[] args) throws InterruptedException{Thread tnew Mythread();t.start();t.join();System.out.println(线程已经结束);}
}代码运行截图 这样我们就可以看的很清楚了线程是顺序执行的。
获取当前线程引用
这个方法就比较简单了可以了解一下代码如下
public class Main {public static boolean flagtrue;public static void main(String[] args) throws InterruptedException{Thread tThread.currentThread();System.out.println(t);}
}休眠当前线程
休眠当前线程其实就是我们用的sleep方法关于这个方法呢我们要知道实际的休眠时间是要大于你设置的休眠时间的。
线程的状态
线程的状态是一个枚举类型Thread.State那么都有哪些状态呢我们来看一下以下代码
public class Main {public static boolean flagtrue;public static void main(String[] args) throws InterruptedException{for(Thread.State state:Thread.State.values()){System.out.println(state);}}
}那么我们接下来来描述以下现成的 这些状态的含义
状态类型状态的含义NEW线程被创建出来但并没有开始行动RUNNABLE可以工作的又分为正在工作或者即将开始工作BLOCKED排队等着其他的事情WAITING排队等着其他的事情TIMED_WAITING排队等待其他的事情TERMINATED工作已经完成
观察线程的所有状态
观察 1: 关注 NEW 、 RUNNABLE 、 TERMINATED 状态的切换 使用isAlive进行线程状态的观察 public class Main {public static boolean flagtrue;public static void main(String[] args) throws InterruptedException{Thread tnew Thread(()-{for(int i0;i5;i){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(正在运行中);}});t.start();while(true) {try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(t.getState());}}
}在运行截图中我们可以看到这里的线程状态有的时候是TIMED_WAITING有时候却又变成了RUNNABLE那么这是为什么会这样呢真的是非常的奇怪其实原因很简单因为我们加的有sleep语句当我们调用state方法进行查看此时线程的状态的时候那么这个线程可能正在执行任务也有可能是正在sleep因此才会出现这种现象
多线程带来的风险
首先多线程会带来怎样的风险呢我们来看一下下面的这个例子
class MyRun{public int run0;public void Run(){run;}
}
public class Main {public static boolean flagtrue;public static void main(String[] args) throws InterruptedException{final MyRun mnew MyRun();Thread t1new Thread(()-{for (int i0;i5000;i)m.Run();System.out.println(t1执行完毕m.run);});Thread t2new Thread(()-{for (int i0;i5000;i)m.Run();System.out.println(t2执行完毕m.run);});t1.start();t2.start();t1.join();t2.join();System.out.println(m.run);}
}他的运行结果是怎么样的呢看下图 另外我在写代码的时候有一个非常傻子的错误那就是把join没写上导致打印结果是0这里原因是因为忽略了线程的并发执行有同样问题的同学可以共勉。
为什么会这样
为什么会这样呢按道理来说不应该是一万吗为什么会发生这种情况呢相信大部分同学都会冒出这样的疑问那么这是为什么呢其实原因很简单因为对于来说你看到的是一个操作其实他的底层是三个指令也就是三个操作正因为是三个操作这就导致了这个操作不是原子的那么就可能出现我们数据库中类似于脏读的情况。那么剩下的内容我会在下一期文章中详细说明 希望往后的日子可以与所爱万般皆顺利。