多线程(2)-Thread类介绍

Java学习总结之多线程(2)

1.Thread类的及常见方法

1.1Thread类的构造方法

方法说明
Thread()创建线程对象
Thread(Runnable target)使用Runnable对象并创建线程对象
Thread(String name)创建线程对象,并命名
Thread(Runnable target,String name))使用Runnable对象创建线程对象,并命名
Thread(ThreadGroup group,Runnable target)线程可以被用来分组管理,分好的组即为线程组

1.2Thread类的几个属性

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否为后台线程idDaemon()
是否存活isAlive()
是否被中断isInterrupted()
  • ID 是线程的唯一标识,不同线程不会重复
  • 名称是各种调试工具用到
  • 状态表示线程当前所处的一个情况,下面我们会进一步说明
  • 优先级高的线程理论上来说更容易被调度到
  • JVM会在一个进程的所有非后台线程结束后,才会结束运行。
  • 是否存活,就是run 方法是否运行结束了

2.线程的常见方法

2.1启动一个线程-start()

  • 调用start()方法,才是真正在操作系统底层创建出一个线程
  • 重写run()方法创建了一个线程对象,但线程对象创建出来并不意味着线程开始运行了
  • 只有调用了start()方法,线程才真正开始运行
//创建线程对象,线程还没有开始运行 
Thread thread = new Thread(()->{
      //业务代码
    Thread thread3 = Thread.currentThread();
    System.out.println("名称" + thread3.getName());
  });
  //启动线程,线程运行
  thread.start();

2.2中断一个线程的两种方式

2.2.1通过共享标记来进行沟通
/**
 * 自定义标识符终止线程
 */
public class InterruptThread1 {
    //声明一个自定义标识符
    private volatile static boolean flag = false;
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while(!flag){
                System.out.println("正在转账");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("差点误了大事");
        });
        thread.start();
        Thread.sleep(10000);
        InterruptThread1.flag = true;  //改变共享标记,中断线程运行
        System.out.println("执行结束");
    }
}
2.2.2调用interrupt()方法来通知

Thread 内部包含了一个 boolean 类型的变量作为线程是否被中断的标记

方法说明
public void interrupt()中断对象关联的线程,如果线程在阻塞,则以异常的方式进行通知,否则设置标记位
public statci boolean interrupted()判断当前线程的中断标志位是否设置,调用后清除标志位
public boolean isInterrupted()判断对象关联的线程的标志位是否设置,调用后不清除标志位
  • 使用thread对象的interrupted()方法通知线程结束
public class InterruptThread1 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while(!Thread.interrupted()){  //或者!Thread.currentThread().isInterrupted()
                System.out.println("正在转账");
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
            System.out.println("差点误了大事");
        });
        thread.start();
        Thread.sleep(10000);
        thread.interrupt();   //通知线程结束
        System.out.println("执行结束");
    }
}

thread收到通知的方式有两种

  1. 如果线程因为调用wait/join/sleep等方法引起阻塞而挂起,则以InterruptedException异常的方式进行通知,清除中断标志
    • 当出现 InterruptedException 的时候, 要不要结束线程取决于 catch 中代码的写法. 可以选择
      忽略这个异常, 也可以跳出循环结束线程.
  2. 否则,只是内部的一个中断标志被设置,thread 可以通过
    • Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
    • Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志

2.3等待一个线程-join()

有时候,我们需要等待一个线程完成它的工作后,才能进行自己的下一步工作。

方法说明
public void join()等待线程结束
public void join(long millis)等待线程结束,最多等millis毫秒
public void join(long millis,)更高精度

2.4获取当前线程引用

方法说明
public static Thread currentThread()返回当前线程对象的引用

2.5休眠当前线程

方法说明
public static void sleep(long millis) throws InterruptedException休眠当前线程 millis 毫秒
public static void sleep(long millis, int nanos) throws InterruptedException可以更高精度的休眠
  • 因为线程调度是不可控的,因此这个方法只能保证实际休眠时间大于等于参数设置的时间

3.线程的状态

状态说明
New新创建
Runnable可运行
Blcoked被阻塞
Waiting等待
Timed waiting计时等待
Terminated被终止
3.1新创建线程

当用 new 操作符创建一个新线程时, 如 newThread®, 该线程还没有开始运行。这意味着它的状态是 new。当一个线程处于新创建状态时, 程序还没有开始运行线程中的代码。在线程运行之前还有一些基础工作要做。

3.2可运行线程
  • 调用线程的start()方法,此线程进入可运行状态。
  • 当前线程sleep()方法结束,其他线程join()结束,等待用户输入完毕,某个线程拿到对象锁,这些线程也将进入可运行状态。
  • 当前线程时间片用完了,调用当前线程的yield()方法,当前线程进入可运行状态。
  • 锁池里的线程拿到对象锁后,进入可运行状态。
3.3被阻塞线程和等待线程

被阻塞线程

阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu 时间片,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu 时间片转到运行(running)状态

  • 当前线程T调用Thread.sleep()方法,当前线程进入阻塞状态。
  • 运行在当前线程里的其它线程t2调用join()方法,当前线程进入阻塞状态。
  • 等待用户输入的时候,当前线程进入阻塞状态
  • BLOCKED 表示等待获取锁, WAITING 和 TIMED_WAITING 表示等待其他线程发来通知.
    TIMED_WAITING 线程在等待唤醒,但设置了时限; WAITING 线程在无限等待唤醒

等待线程

  • 当线程等待另一个线程通知调度器一个条件时, 它自己进入等待状态 在调用 Object.wait 方法或 Thread.join 方法, 或者是等待 java.util.concurrent 库中的 Lock 或 Condition 时, 就会出现这种情况。实际上,被阻塞状态与等待状态是有很大不同的
  • 有几个方法有一个超时参数。调用它们导致线程进人计时等待( timed waiting) 状态。这一状态将一直保持到超时期满或者接收到适当的通知。带有超时参数的方法有Thread.sleep 和 Object.wait、 Thread.join、 Lock,tryLock 以及 Condition.await 的计时版。

结论

  • BLOCKED 表示等待获取锁, WAITING 和 TIMED_WAITING 表示等待其他线程发来通知.
  • TIMED_WAITING 线程在等待唤醒,但设置了时限; WAITING 线程在无限等待唤醒
3.5被终止线程
  • 当线程的run()方法完成时,或者主线程的main()方法完成时,我们就认为它死去。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。线程一旦死亡,就不能复生。
  • 在一个死去的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常

4.线程状态的转移

4.1关注 NEW 、 RUNNABLE 、 TERMINATED 状态的转换

使用 isAlive 方法判定线程的存活状态

public class ThreadStateTransfer {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            for (int i = 0; i < 1000_0000; i++) {
            }
        }, "李四");
        System.out.println(t.getName() + ": " + t.getState());;
        t.start();
        while (t.isAlive()) {
            System.out.println(t.getName() + ": " + t.getState());;
        }
        System.out.println(t.getName() + ": " + t.getState());;
    }
}
4.2yield() 大公无私,让出 CPU
public class ThreadYield {
    public static void main(String[] args) {
        Thread thread  = new Thread(() ->{
            Thread t1 = Thread.currentThread();
            for (int i = 0; i < 10; i++) {
                //让出CPU执行权
                Thread.yield();
                System.out.println("执行了线程" + t1.getName());
            }
        },"张三");
        thread.start();
        //创建并启动线程
        new Thread(() -> {
            Thread t1 = Thread.currentThread();
            for (int i = 0; i < 10; i++) {
                System.out.println("执行了线程" + t1.getName());
            }
        },"李四").start();
    }
  • yield 不改变线程的状态, 但是会重新去排队

5.线程的生命周期

  • 新建:创建线程对象
  • 就绪:线程有执行资格,没有执行权
  • 运行:有执行资格,有执行权
  • 阻塞:由于一些操作让线程改变了状态,没有执行资格,没有执行权,另一些操作可以把它给激活,激活处于就绪状态
  • 死亡:线程对象变成垃圾,等待被回收
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值