• 线程的方法(未完成)


    线程的方法

    1.获取当前线程对象:CurrentThread()

    1. @Test
    2. public void bb() {
    3. Thread thread = Thread.currentThread();
    4. System.out.println(thread.getName());//打印 main
    5. }

    2.currentThread().setName和currentThread().getName

    1. @Test
    2. public void bb() {
    3. Thread.currentThread().setName("heihei");
    4. String name = Thread.currentThread().getName();
    5. System.out.println(name); // 打印 heihei
    6. }

    3.currentThread().isAlive()

    判断当前线程是否正在执行

    1. @Test
    2. public void bb() {
    3. MyThread mt = new MyThread() ; // 实例化Runnable子类对象
    4. Thread t = new Thread(mt,"线程"); // 实例化Thread对象
    5. System.out.println("线程开始执行之前 --> " + t.isAlive()) ; // 打印结果:线程开始执行之前 --> false
    6. t.start() ; // 启动线程
    7. System.out.println("线程开始执行之后 --> " + t.isAlive()) ; // 打印结果:线程开始执行之前 --> true
    8. }

    4.start()与run()

    调用start()方法才是 启动一个新的线程。

    调用run()方法只是主线程调用了一个类的一个普通方法.并没有开启一个新线程.

    1. @Test
    2. public void bb() {
    3. MyThread myThread = new MyThread();
    4. myThread.start(); //打印 Thread-2运行了
    5. myThread.run(); //打印 main方法运行了
    6. }

    5.join()/join(long millis)

    将两个线程绑定在一起,看成是共同体,B线程执行完成后,必然执行A线程.

    join()就是A无限期等待,当B线程执行完,A线程才执行

    join(1000)就是A只等待1000毫秒

    如果B 500毫秒执行完了,那么 A就直接结束等待时间,直接被唤醒

    如果A等待1000毫秒后,B还没执行完,那A也不等了,就直接被唤醒和B一块并发执行

    底层其实就是A线程被wait,下面是底层代码

    1. public final synchronized void join(long millis)
    2. throws InterruptedException {
    3. long base = System.currentTimeMillis();
    4. long now = 0;
    5. if (millis < 0) {
    6. throw new IllegalArgumentException("timeout value is negative");
    7. }
    8. if (millis == 0) {
    9. while (isAlive()) {//只要B线程还没结束,A线程就会一直阻塞
    10. wait(0);//这里的wait调用的本地方法。
    11. }
    12. } else {//等待一段指定的时间
    13. while (isAlive()) {
    14. long delay = millis - now;
    15. if (delay <= 0) {
    16. break;
    17. }
    18. wait(delay);
    19. now = System.currentTimeMillis() - base;
    20. }
    21. }
    22. }

    下面是例子

    1. @Test
    2. public void bb() {
    3. MyBThread myThread = new MyBThread();
    4. myThread.start();
    5. for (int i = 0; i < 15; i++) {
    6. if(i>5){
    7. try{
    8. myThread.join() ; // 线程强制运行
    9. }catch(InterruptedException e){}
    10. }
    11. System.out.println("Main线程运行 --> " + i) ;
    12. }
    13. }
    14. }
    15. class MyBThread extends Thread{
    16. @Override
    17. public void run(){
    18. for (int i = 0; i < 15; i++) {
    19. System.out.println(Thread.currentThread().getName()+"运行了,i="+i);
    20. }
    21. }
    22. }
    1. Main线程运行 --> 0
    2. Main线程运行 --> 1
    3. Main线程运行 --> 2
    4. Main线程运行 --> 3
    5. Main线程运行 --> 4
    6. Main线程运行 --> 5
    7. Thread-2运行了,i=0
    8. Thread-2运行了,i=1
    9. Thread-2运行了,i=2
    10. Thread-2运行了,i=3
    11. Thread-2运行了,i=4
    12. Thread-2运行了,i=5
    13. Thread-2运行了,i=6
    14. Thread-2运行了,i=7
    15. Thread-2运行了,i=8
    16. Thread-2运行了,i=9
    17. Thread-2运行了,i=10
    18. Thread-2运行了,i=11
    19. Thread-2运行了,i=12
    20. Thread-2运行了,i=13
    21. Thread-2运行了,i=14
    22. Main线程运行 --> 6
    23. Main线程运行 --> 7
    24. Main线程运行 --> 8
    25. Main线程运行 --> 9
    26. Main线程运行 --> 10
    27. Main线程运行 --> 11
    28. Main线程运行 --> 12
    29. Main线程运行 --> 13
    30. Main线程运行 --> 14

    6.yield()

    yield() 暂停当前方法,释放自己拥有的CPU,线程进入就绪状态。它能让当前线程由“运行状态”进入到“就绪状态”,然后和其他优先级比它高的或者和它相同的线程一起去重新争抢cpu的使用.

    优先级高的线程抢到cpu的概率较大,但是不一定会第一个抢到,  因为这还和操作系统的调度和cpu的执行有关系.  建议少用.

    7.sleep(long millis)

    线程休眠:让执行的线程暂停一段时间,进入计时等待状态。
    static void sleep(long millis):调用此方法后,当前线程放弃 CPU 资源,在指定的时间内,sleep 所在的线程不会获得可运行的机会,此状态下的线程不会释放同步锁
    该方法更多的是用来模拟网络延迟,让多线程并发访问同一资源时的错误效果更加明显。

    8.wait()和notify()/notifyAll()

    wait()/wait(long timeout)/wait(long timeout, int nanos)

    先看一看wait的三个重载方法

    • public final void wait() throws InterruptedException
    • public final void wait(long timeout) throws InterruptedException
    • public final void wait(long timeout, int nanos) throws InterruptedException

    方法参数

    timeout - 等待时间(以毫秒为单位)。

    nanos - 额外等待时间(以纳秒为单位)。

    wait()相当于调用wait(0),0表示永远不超时。让当前线程处于等待状态,只有调用对象的notify或者notifyAll才能将其唤醒.

    wait(1000):等待1000毫秒, 让当前线程处于计时等待状态,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过参数 timeout设置的超时时间才能将其唤醒.

    wait(1000,50):等待1000毫秒+50纳秒, 让当前线程处于计时等待状态,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过参数 timeout 加上 nanos 设置的超时时间才能将其唤醒.

    notify()/notifyAll()

    唤醒:notify()-随机唤醒wait的一个线程,notifyAll()-唤醒所有线程
    注意:此方法需和wait()成对使用,必须在同步代码块或同步方法中

    上面的方法必须在同步代码块或同步方法中

    每一个对象都有一个跟它关联的monitor,只有获取到对象的monitor才能调用对象的wait方法和调用对象的notify和notifyAll方法。也就是说wait,notify,notifyAll都必须在对象的synchronized同步方法里面调用。如果wait没有在对象的synchronized同步块里面执行会抛出

    java.lang.IllegalMonitorStateException
    

     结束线程的方法

    1.线程正常自动结束

    2.使用标准位终结线程

    一般 run()方法执行完,线程就会正常结束,然而,常常有些线程是伺服线程。它们需要长时间的运行,只有在外部某些条件满足的情况下,才能关闭这些线程。使用一个变量来控制循环,例如: 最直接的方法就是设一个boolean类型的标志,并通过设置这个标志为true或false来控制while 循环是否退出,代码示例:

    1. @RestController
    2. @RequestMapping("/test")
    3. public class Docx4jOfficeFileToPDF {
    4. public static void main(String args[]) throws InterruptedException {
    5. MyBThread mt = new MyBThread() ;
    6. mt.start();
    7. Thread.sleep(1);//主线程等待1ms
    8. mt.exit = true; //修改标志位,退出线程
    9. }
    10. }
    11. class MyBThread extends Thread{
    12. //volatile修饰符用来保证其它线程读取的总是该变量的最新的值
    13. public volatile boolean exit = false;
    14. @Override
    15. public void run() {
    16. int i =1;
    17. while(!exit){
    18. System.out.println(i++);
    19. }
    20. System.out.println("结束");
    21. }
    22. }

    定义了一个退出标志exit,当exit为true时,while循环退出,exit的默认值为false.在定义exit 时,使用了一个 Java 关键字 volatile,这个关键字的目的是使 exit 同步,也就是说在同一时刻只 能由一个线程来修改exit的值。 

     3.interrupt()

     interrupt() 方法仅仅是在当前线程中打一个停止的标记,并不是真的停止线程。

    ① 如果线程使用了 sleep,同步锁的 wait,socket 中的 receiver,accept 等方法时, 会使线程处于阻塞状态。当sleep()等方法和interrupt() 方法相遇时.sleep()等方法会抛出 InterruptException 异常,并清除掉线程的中断标识.

    ② 如果线程处于正常活动状态,那么会将该线程的中断标志设置为 true,仅此而已。被设置中断标志的线程将继续正常运行,丝毫不受影响。

    所以我们只有手动去停止线程,我们需要配合下面的两个方法,来手动写停止逻辑代码,以达到手动停止线程的目的

    1. public boolean Thread.isInterrupted() //判断是否被中断
    2. public static boolean Thread.interrupted() //判断是否被中断,并清除当前中断状态

    实验得知:

    1.在线程sleep()阻塞的时候, 线程再去调 interrupt()方法,会抛出 InterruptException 异常

    2.在线程调完interrupt()方法,有中断标识的时候,  线程再去调sleep()方法.也会抛出InterruptException 异常

    因此,实验得出下面的代码100%能结束线程.

    1. public class Docx4jOfficeFileToPDF {
    2. public static void main(String args[]) throws InterruptedException {
    3. MyBThread mt = new MyBThread() ;
    4. mt.start();//子线程执行
    5. mt.interrupt();//给子线程加上中断标志
    6. }
    7. }
    8. class MyBThread extends Thread{
    9. @Override
    10. public void run() {
    11. while (true){
    12. try{
    13. Thread.sleep(500000);//阻塞过程捕获中断异常来退出
    14. }catch(InterruptedException e){
    15. e.printStackTrace();
    16. break;//捕获到异常之后,执行break跳出循环,相当于结束子线程
    17. }
    18. }
    19. }
    20. }

    或者用interrupt()当做标准位终止线程的那种方式

    1. @RestController
    2. @RequestMapping("/test")
    3. public class Docx4jOfficeFileToPDF {
    4. public static void main(String args[]) throws InterruptedException {
    5. MyBThread mt = new MyBThread() ;
    6. mt.start();
    7. mt.interrupt(); //修改标志位,退出线程
    8. }
    9. }
    10. class MyBThread extends Thread{
    11. @Override
    12. public void run() {
    13. int i =1;
    14. while(!isInterrupted()){
    15. System.out.println(i++);
    16. }
    17. System.out.println("结束");
    18. }
    19. }

     4.stop ()

    此方法已被弃用,不安全.

    为什么弃用stop:

    1. 调用 stop() 方法会立刻停止 run() 方法中剩余的全部工作,包括在 catch 或 finally 语句中的,并抛出ThreadDeath异常(通常情况下此异常不需要显示的捕获),因此可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。
    2. 调用 stop() 方法会立即释放该线程所持有的所有的锁,导致数据得不到同步,出现数据不一致的问题。
    3. stop()方法被try-catch()后会失效.

    例如,存在一个对象 u 持有 ID 和 NAME 两个字段,假如写入线程在写对象的过程中,只完成了对 ID 的赋值,但没来得及为 NAME 赋值,就被 stop() 导致锁被释放,那么当读取线程得到锁之后再去读取对象 u 的 ID 和 Name 时,就会出现数据不一致的问题

    1. @RestController
    2. @RequestMapping("/test")
    3. public class Docx4jOfficeFileToPDF {
    4. public static void main(String args[]){
    5. MyBThread mt = new MyBThread() ;
    6. mt.start();
    7. }
    8. }
    9. class MyBThread extends Thread{
    10. @Override
    11. public void run(){
    12. System.out.println("运行了111");
    13. this.stop();
    14. System.out.println("运行了222");
    15. }
    16. }
    运行了111

  • 相关阅读:
    【Java】文件操作篇(三)字符输入流、字符输出流及常用子类
    C#中的双缓冲(转)
    奖品定制经营商城小程序的作用是什么
    HTML入门教程23:HTML脚本
    降维算法之奇异值分解 (Singular Value Decomposition, SVD)
    为什么手机和电视ip地址不一样
    nacos-v2.1.0持久化
    ActiveRecord::Migration.maintain_test_schema!
    【LeetCode】35. 搜索插入位置
    采购自动化如何帮助采购转型?
  • 原文地址:https://blog.csdn.net/weixin_70280523/article/details/132957550