Java多线程基础梳理

Java给多线程编程提供了内置的支持。一条线程指的是进程中(正在运行的一个应用,包括操作系统分配的内存空间,一个或者多个线程)的一个单一顺序的控制流,一个进程中可以并发执行多个线程,没个线程并发的执行不同的任务。

多线程是多任务的一种特别的形式,但是多线程使用了更小的资源开销。

一个线程的生命周期

java Stack 多线程 java 多线程详解_创建线程

  • 新建状态
  • 使用new关键字和Thread类或其子类建立一个线程对象后,该线程就处于新建状态。它保持这个状态直到程序start()这个线程。
  • 就绪状态
  • 当线程对象调用start()方法之后,该线程就处于就绪状态。就绪状态的线程处于就绪队列中,要等待JVM中线程调度器的调度。
  • 运行状态
  • 如果就绪状态的线程获取CPU资源,就可以执行run()方法,此时线程处于运行状态。
  • 阻塞状态
  • 如果一个线程执行了sleep(睡眠)、suspend(挂起)等方法,失去所占用资源之后,该线程就从运行状态进入阻塞状态。在睡眠时间已到或获得设备资源后可以重新进入就绪状态。可以分为三种:
  • 等待阻塞:运行状态中的线程执行 wait() 方法,使线程进入到等待阻塞状态。
  • 同步阻塞:线程在获取 synchronized 同步锁失败(因为同步锁被其他线程占用)。
  • 其他阻塞:通过调用线程的 sleep() 或 join() 发出了 I/O 请求时,线程就会进入到阻塞状态。当sleep() 状态超时,join() 等待线程终止或超时,或者 I/O 处理完毕,线程重新转入就绪状态。
  • 死亡状态
  • 一个运行状态的线程完成任务或者其他终止条件触发时,该线程就切换为死亡状态。

如何创建一个线程

继承Thread类

创建线程的第一个方法就是继承Thread类,该类必须重写Thread中的run()方法,run()方法是新线程的入口点,调用的时候必须使用start方法才能够执行。

//创建TestThread01继承Thread类
//注意:线程开启之后不一定立即执行,线程执行由CPU统一调度
public class TestThread01 extends Thread{
    
    
    //重写run()方法
    @Override
    public  void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("");
        }
    }

    public static void main(String[] args) {
        
        //创建一个类对象(该类继承了Thread)
        TestThread01 testThread01 = new TestThread01();
        
        //调用start方法开启线程
        testThread01.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("");
        }
    }
}

小结

  • 子类继承Thread类具备多线程能力
  • 启动线程:子类对象.start()
  • testThread01.start();
  • 不建议使用,避免OOP单继承局限性

实现Runnable接口

创建线程的第二个方法就是实现Runnable接口,该类也需要重写run()方法,将需要执行的线程放置到Runnable接口的实现类中,调用start()方法执行

//创建线程方式2.实现Runnable接口,重写run方法,执行线程需要丢入Runnable接口的实现类,调用start方法
public class TestThread02 implements Runnable{

    //重写run()方法
    @Override
    public void run() {
        ......
    }

    public static void main(String[] args) {
        //创建Runnable接口实现类对象
        TestThread02 testThread02 = new TestThread02();

        //创建线程对象,通过线程对象来开启我们的线程
        //new Thread(testThread02).start();
        Thread thread = new Thread(testThread02);
        thread.start();
    }
}

小结

  • 实现接口Runnable具有多线程能力
  • 启动线程:传入目标对象.Thread对象.start()
  • new Thread(目标对象).start();
  • 推荐使用,避免单继承局限性,灵活方便,方便同一个对象呗多个线程调用

通过Callable创建线程

1.实现Callable接口,需要返回值类型

2.重写call方法,需要抛出异常

3.创建目标对象

4.创建执行任务:ExecutorService ser = Executors.newFixedThreadPool(1);

5.提交执行:Future<Boolean> result = ser.submit(t1);

6.获取结果:boolean r1 = result.get()

7.关闭服务:ser.shutdown();

import java.util.concurrent.*;

//实现Callable方式创建线程
public class TestThread05 implements Callable<Boolean> {

    //重写call()方法
    @Override
    public Boolean call() throws Exception {
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {

        //设置类对象
        TestThread05 testThread05 = new TestThread05();

        //创建执行任务,此处创建了1个线程
        ExecutorService service = Executors.newFixedThreadPool(1);

        //提交执行
        Future<Boolean> r1 = service.submit(testThread05);

        //获取结果
        boolean rs1 = r1.get();

        //关闭服务
        service.shutdownNow();
    }
}