2.线程基础

126 阅读3分钟

一、线程创建的两种主要方式


  • 继承thread类:定义一个继承自Thread的子类并重写该类的run()方法,run方法是线程要完成的任务,因此我们称之为执行体
public class RunnableThreadCreate implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
@Test
public void createByRunnable() {
    Runnable target = new RunnableThreadCreate();
    Thread thread = new Thread(target,"线程一");
    thread.start();
    System.out.println(Thread.currentThread().getName());
}
  • 实现Runnable接口:定义一个实现了Runnable接口的类,将该类的实例作为target传入Thread的构造方法,Thread类的实例才是我们要操作的线程
/**
 * @Date 2022/2/14 13:58
 * @Author mawkun
 */
public class ThreadCreate extends Thread {
    //设置线程名称
    public ThreadCreate(String name) {
        this.setName(name);
    }
​
    @Override
    public void run() {
        super.run();
        System.out.println(Thread.currentThread().getName());
    }
}
@Test
public void createByThread() {
    ThreadCreate threadCreate = new ThreadCreate("线程一");
    threadCreate.start();
    System.out.println(Thread.currentThread().getName());
}

比较两种创建线程方式的优劣:

  • 实现Runnable接口可以避免java不能多继承的劣势
  • 实现Runnable更能体现资源共享的概念,适合相同的代码处理共享的资源
  • 增加程序的健壮性,代码和数据分离
  • 线程池中只可以放入实现了Runnable或callable接口的线程

二、线程的生命周期

image.png

  1. 新建状态(New) :线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()。

  2. 就绪状态(Runnable) :也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。

  3. 运行状态(Running) :线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。

  4. 阻塞状态(Blocked) : 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。

    阻塞的情况分三种:

    • 等待阻塞 -- 通过调用线程的wait()方法,让线程等待某工作的完成。
    • 同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
    • 其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
  5. 死亡状态(Dead)****:线程执行完了或者因异常退出了run()方法,该线程结束生命周期

三、线程状态控制

image.png

  1. start() 启动当前线程,调用当前线程的run()方法
  2. run() 通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
  3. yield() 释放当前CPU执行权
  4. join() 在线程a中调用线程b的join(),此时线程a进行阻塞状态,直到线程b完成执行完以后,线程a结束阻塞
  5. sleep(long militime) 让线程睡眠指定的毫秒数,在指定时间内,线程是阻塞状态
  6. wait() 一旦执行此方法,当前线程就会进入阻塞一旦执行wait()会释放同步监听器
  7. noity() 执行此方法,将会唤醒被wait的一个线程,如果有多个wait状态线程,唤醒优先度最高的
  8. noityAll() 执行此方法,唤醒所有被wait的线程

sleep和wait比较:

  • 相同点:sleep和wait都会让线程进入阻塞状态
  • 不同点
    1. Thread类中声明sleep(),Object类中声明wait()
    2. 调用要求不同,sleep()方法可以在任何需要的场景下调用,wait()必须在同步代码块中调用
    3. 如果两个方法都在同步方法或者同步代码块中使用,sleep不会释放锁,wait会释放锁