Thread 类常见属性

目录

目录

一.举例示范常见属性

二.休眠一个线程

三.获取线程引用

四.中断一个线程(interrupt)

1. 不执行中断

 2.立即执行中断

 3. 稍后再执行中断

五. 等待一个线程(join)

六.获取线程的状态 (state)



Thread 类常见属性_第1张图片

  • ID 是线程的唯一标识,不同线程不会重复
  • 名称是各种调试工具用到
  • 状态表示线程当前所处的一个情况,下面我们会进一步说明
  • 优先级高的线程理论上来说更容易被调度到
  • 关于后台线程,需要记住一点:JVM会在一个进程的所有非后台线程结束后,才会结束运行。
  • 是否存活,即简单的理解,为 run 方法是否运行结束了
  • 是否被中断,重点,下面会详细介绍

一.举例示范常见属性

程序举例,有以下程序(Thread.currentThread()表示返回当前线程对象的引用)

package thread;

public class NINNI {
        public static void main(String[] args) {
            //以下是thread线程中的
            Thread thread = new Thread(() -> {
                for (int i = 0; i < 10; i++) {
                    try {
                        System.out.println(Thread.currentThread().getName() + ": 我还活着");
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName() + ": 我即将死去");
            },"迷途知返209");

            //以下时Main线程中的
            System.out.println(Thread.currentThread().getName()
                    + ": ID: " + thread.getId());
            System.out.println(Thread.currentThread().getName()
                    + ": 名称: " + thread.getName());
            System.out.println(Thread.currentThread().getName()
                    + ": 状态: " + thread.getState());
            System.out.println(Thread.currentThread().getName()
                    + ": 优先级: " + thread.getPriority());
            System.out.println(Thread.currentThread().getName()
                    + ": 后台线程: " + thread.isDaemon());
            System.out.println(Thread.currentThread().getName()
                    + ": 活着: " + thread.isAlive());
            System.out.println(Thread.currentThread().getName()
                    + ": 被中断: " + thread.isInterrupted());
            thread.start();
            while (thread.isAlive()) {}
            System.out.println(Thread.currentThread().getName()
                    + ": 状态: " + thread.getState());
        }
    }


代码解读

此代码一共创建了两个线程,一个是main线程,另一个是命名的“迷途知返209”

这两个线程同时执行,当main执行的时候,由于“迷途知返209”线程需要循坏,并且每次循环都要等待1秒,那么肯定main线程中的语句先执行~~~

二.休眠一个线程

public class ThreadDemo {
	public static void main(String[] args) throws InterruptedException {
		System.out.println(System.currentTimeMillis());
		Thread.sleep(3 * 1000);
		System.out.println(System.currentTimeMillis());
	}
}

此时的代码执行到Tread.sleep的时候,会进行休眠,将自己添加到阻塞队列,也就是从CPU上暂时下来。

三.获取线程引用

public class ThreadDemo {
	public static void main(String[] args) {
		Thread thread = Thread.currentThread();
		System.out.println(thread.getName());
	}
}

此时就获取到了当前 thread 线程的名字 默认是thread-0; 

四.中断一个线程(interrupt)

线程中断的意思大体是这样的:假如 张三有个老婆叫西施 。 我们假设西施是 main线程,张三是另一个t 线程。张三正在执行着 “打游戏 ”的线程。此时西施(main线程)让张三(t线程)停下来去买瓶酱油,那么此时的张三面临着三种选择:

1.放下游戏,立马去买酱油(立即执行中断)

2.不放下游戏,打完最后一波团,再去买酱油(稍后再执行中断)

3.假装没听见,一直打游戏(不执行中断)

那么再代码中我们可以这样写:

1. 不执行中断

    public static void main(String[] args) throws InterruptedException {
        /**
         * 此处实现进程中断
         * 第一种  ↓
         * 是main线程告诉t要终止,但是t里面的具体实现是  不执行任何操作
         */
        Thread t = new Thread(()-> {
            //interrupt执行后,唤醒sleep,清楚标志位(改为false),循环仍然可以进去,线程不会结束
           while (!Thread.currentThread().isInterrupted()) {
               System.out.println("Hello thread");
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        });
        t.start();
        Thread.sleep(3000);

        t.interrupt();   //sleep唤醒,清楚标志位  改为false
    }

运行结果:

Thread 类常见属性_第2张图片

此时程序会一直走,原因如下:

如果看不清该图(劳烦放大~~~)

Thread 类常见属性_第3张图片

 2.立即执行中断

   public static void main(String[] args) throws InterruptedException {
        /**
         * 此处实现进程中断
         * 第二种  ↓
         * 是main线程告诉t要终止,t里面的具体实现是 立刻乖乖听话,停止
         */
        Thread t = new Thread(()-> {
            //本来是假,现在取反为真
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("Hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;   //此处异常之后,立马退出
                }
            }
        });
        t.start();
        Thread.sleep(3000);

        t.interrupt();
    }

此处在发生异常之后,直接就break掉了循环,也就是立即终止了进程

运行结果:

Thread 类常见属性_第4张图片

 3. 稍后再执行中断

    public static void main(String[] args) throws InterruptedException {
        /**
         * 此处实现进程中断
         * 第三种  ↓
         * 是main线程告诉t要终止,t里面的具体实现是 我等一会再终止
         */
        Thread t = new Thread(()-> {
            //本来是假,现在取反为真
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("Hello thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    System.out.println("等一等~");
                    try {
                        Thread.sleep(3000);    //进程稍后退出
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    break;
                }
            }
        });
        t.start();
        Thread.sleep(3000);

        t.interrupt();
    }

此时在执行break之前,又增加了一段Thread.sleep(3000); 代码,也就是t 线程等待3秒之后,再执行break语句;

五. 等待一个线程(join)

关于其join相关的方法入下:

其中无参数版本的是 死等 ,必须等到另一个线程结束再罢休。

第二个和第三个 是等待一定的时间,等不到就算了~。

Thread 类常见属性_第5张图片

原本线程之间是并发执行的,当引入 join 之后,两个线程就会有一个线程发生阻塞,也就是会有一个线程去等待另一个线程。我们先来看以下代码

package thread;

public class ThreadDemo8Join {

    public static void main(String[] args) {
        /**
         * 原本进程之间是并发执行,引入Join之后,当Main线程执行到 Join 后,会先发生阻塞.等待 t 线程执行完 (等小孩放学)
         * 假设开始执行 Join的时候, t 已经结束了,此时 Join 便不会再阻塞 (孩子已经放学了)
         * 如果不加Join , 那么 Main 线程 和 t 线程就是抢占式执行方式
         */
        Thread t = new Thread(()-> {
            for (int i = 0; i < 3; i++) {
                System.out.println("我是 t 线程! main线程现在阻塞了,在等我");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();

                }
            }
        });

        t.start();
        System.out.println("Join之前");

       // 此处的 join 就是让当前的 main 线程来等待 t 线程结束
        try {
            t.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Join之后,此时 t 线程已经走完啦");
    }
}

代码解读:

1.首先我们要清楚,这个代码中有两个线程 Main线程 和 t 线程。

2.当 t.strat()线程启动之后,此时 Main 线程和 t 线程在一起跑

3.当 Main 线程执行到 t.join 的时候,此时 Main 线程阻塞(也即是不能在继续往下走了),此时 t 线程还在继续走,且 t 线程走完之后, Main 线程才可以继续走。

运行结果如下:

Thread 类常见属性_第6张图片

六.获取线程的状态 (state)

线程的状态是一个枚举类型 Thread.State
 

package thread;

public class StateTest {
        public static void main(String[] args) {
            for (Thread.State state : Thread.State.values()) {
                System.out.println(state);
            }
        }
    }

运行结果

Thread 类常见属性_第7张图片

 线程的状态解释

  1. NEW: 安排了工作, 还未开始行动
  2. RUNNABLE: 可工作的. 又可以分成正在工作中和即将开始工作.
  3. BLOCKED: 这几个都表示排队等着其他事情
  4. WAITING: 这几个都表示排队等着其他事情
  5. TIMED_WAITING: 这几个都表示排队等着其他事情
  6. TERMINATED: 工作完成

这样文字可能不太好理解,我们借助以下例子表示 :

~~~~~~假如你是百万富翁,你让你的两个手下张三和李四去银行取钱~~~~~~

刚把李四、王五找来,还是给他们在安排任务,没让他们行动起来,就是 NEW 状态;
当李四、王五开始去窗口排队,等待服务,就进入到 RUNNABLE 状态。该状态并不表示已经被银行工作人员开始接待,排在队伍中也是属于该状态,即可被服务的状态,是否开始服务,则看调度器的调度;

当李四、王五因为一些事情需要去忙,例如需要填写信息、回家取证件、发呆一会等等时,进入BLOCKED 、 WATING 、 TIMED_WAITING 状态,至于这些状态的细分,我们以后再详解;
如果李四、王五已经忙完,为 TERMINATED 状态
 

代码示例:

package thread;

public class ThreadDemo9State {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(()-> {
            for (int i = 0; i < 100; i++) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        //启动之前,获取t的状态,就是NEW状态
        System.out.println("启动之前 " + t.getState());
        t.start();
        for (int i = 0; i < 1000; i++) {
            //通过这里的循环获取,就能够看到这里的交替状态了,具体获取到什么,完全取决于系统里的调度操作
            // 如果正在执行-->RUNNABLE      如果正在Sleep ----> TIMED_WAITING;
            System.out.println("执行之中的状态:" + t.getState());
        }
        t.join();  //执行这个Join , main和t这两个线程就不会并发执行,而是main等待t执行完再执行,也就是t单独执行完

        //线程结束之后, 就是 TERMINATED(终止) 状态
        System.out.println("启动之后 " + t.getState());

    }
}

代码解读:

1. t.start() 之前,线程已经准备好了,所以是NEW状态

2. t.start() 之后,此时就有两个线程 main线程 和 t 线程

3. 两个线程同时执行 ,由于 main线程中写的代码少,可能会很快结束,所以加了个循环,此时可以看到 t 线程的状态

4. 假如执行到 t 线程此时正在 sleep ,那么就是TIMED_WAITING

5. 假如执行到 t 线程此时没有sleep , 那么就是RUNNABLE

6. 执行到t.join() 是防止 main线程比 t 线程 提前走完。执行这个Join , main和t这两个线程就不会并发执行,而是main等待 t 执行完再执行,也就是  t  单独执行完。

7. 走到最后,t 一定执行完了,再此查看状态 就是TERMINATED。

本篇博客结束

下回讲解  多线程带来的的风险-线程安全 (重点)~~~
 

你可能感兴趣的:(java,jvm,开发语言)