目录
  • 1. 线程是什么
  • 2. 怎样创建线程
    • 2.1 继承Thread类
    • 2.2 实现Runnable接口
    • 2.3 实现Callable接口
    • 2.4 使用线程池创建
  • 3. 线程的状态
    • 4. 线程常用方法

      1. 线程是什么

      操作系统支持多个应用程序并发执行,每个应用程序至少对应一个进程 ,彼此之间的操作和数据不受干扰,彼此通信一般采用管道通信、消息队列、共享内存等方式。当一个进程需要磁盘IO的时候,CPU就切换到另外的进程,提高了CPU利用率。

      有了进程,为什么还要线程?因为进程的成本太高了。

      启动新的进程必须分配独立的内存空间,建立数据表维护它的代码段、堆栈段和数据段,这是昂贵的多任务工作方式。线程可以看作轻量化的进程。线程之间使用相同的地址空间,切换线程的时间远小于切换进程的时间。

      进程是资源分配的最小单位,而线程是CPU调度的最小单位。每一个进程中至少有一个线程,同一进程的所有线程共享该进程的所有资源,多个线程可以完成多个不同的任务,也就是我们常说的并发多线程。

      2. 怎样创建线程

      创建线程常用的有四种方式,分别是:

      • 继承Thread类
      • 实现Runnable接口
      • 实现Callable接口
      • 使用线程池创建

      分别看一下怎么具体怎么使用代码创建的?

      2.1 继承Thread类

      public class ThreadDemo {
      
          public static void main(String[] args) {
              Thread thread = new MyThread();
              thread.start(); // 启动线程
          }
      }
      
      class MyThread extends Thread {
          @Override
          public void run() {
              System.out.println("关注公众号:一灯架构");
          }
      }
      

      输出结果:

      关注公众号:一灯架构

      start方法用来启动线程,只能被调用一次。

      run方法是线程的核心方法,业务逻辑都写在run方法中。

      2.2 实现Runnable接口

      public class ThreadDemo {
      
          public static void main(String[] args) {
      				MyRunnable myRunnable = new MyRunnable();
              Thread thread1 = new Thread(myRunnable, "线程1");
              Thread thread2 = new Thread(myRunnable, "线程2");
              thread1.start(); // 启动线程1
              thread2.start(); // 启动线程2
          }
      }
      
      class MyRunnable implements Runnable {
          private int count = 5;
      
          @Override
          public void run() {
              while (count > 0) {
                  System.out.println(Thread.currentThread().getName()
                          + ",关注公众号:一灯架构," + count--);
              }
          }
      }
      

      输出结果:

      线程2,关注公众号:一灯架构,4
      线程1,关注公众号:一灯架构,5
      线程1,关注公众号:一灯架构,2
      线程1,关注公众号:一灯架构,1
      线程2,关注公众号:一灯架构,3

      需要把Runnable实例放到Thread类中,才能执行,Thread对象才是真正的线程对象。

      使用实现Runnable接口创建线程方式,相比继承Thread类创建线程,优点是:

      • 实现的方式没有类的单继承性的局限性
      • 实现的方式更适合来处理多个线程有共享数据的情况

      2.3 实现Callable接口

      public class ThreadTest {
          public static void main(String[] args) throws ExecutionException, InterruptedException {
              MyCallable myCallable = new MyCallable();
              FutureTask<String> futureTask = new FutureTask<String>(myCallable);
              Thread thread = new Thread(futureTask);
              thread.start();
              System.out.println(futureTask.get());
          }
      }
      
      class MyCallable implements Callable {
          @Override
          public String call() throws Exception {
              return "关注公众号:一灯架构";
          }
      }
      

      输出结果:

      关注公众号:一灯架构

      实现Callable接口的线程实例对象,配合FutureTask使用,可以接收返回值。

      2.4 使用线程池创建

      public class ThreadDemo {
      
          public static void main(String[] args)  {
              ExecutorService executorService = Executors.newFixedThreadPool(10);
              executorService.execute(() -> System.out.println("关注公众号:一灯架构"));
          }
      }
      

      输出结果:

      关注公众号:一灯架构

      使用线程池创建线程是工作开发中最常用的方式,优点是:

      • 线程池帮忙管理对象的创建与销毁,减轻开发者工作量
      • 线程池帮忙管理任务的调用,资源的创建与分配
      • 复用线程和对象,提高使用效率

      3. 线程的状态

      线程共有6种状态,分别是NEW(初始化)、RUNNABLE(可运行)、WAITING(等待)、TIMED_WAITING(超时等待)、BLOCKED(阻塞)、TERMINATED(终止)。

      1.NEW(初始化)

      表示创建线程对象之后,还没有调用start方法。

      2.RUNNABLE(可运行)

      表示调用start方法之后,等待CPU调度。为了便于理解,通常又把RUNNABLE分别RUNNING(运行中)和READY(就绪)。处在RUNNING(运行中)状态的线程可以调用yield方法,让出CPU时间片,然后跟其他处于READY(就绪)一起等待被调度。

      3.WAITING(等待)

      处于RUNNABLE状态的线程调用wait方法之后,就处于等待状态,需要其他线程显示地唤醒。

      4.TIMED_WAITING(超时等待)

      处于RUNNABLE状态的线程调用wait(long)方法之后,就处于等待状态,需要其他线程显示地唤醒。

      5.BLOCKED(阻塞)

      等待进入synchronized方法/代码块,处于阻塞状态。

      6.TERMINATED(终止)

      表示线程已经执行结束。

      Java基础夯实之线程问题全面解析

      4. 线程常用方法

      说一下线程有哪些常用的方法。

      方法定义 含义 使用方式
      public synchronized void start() {……} 启动线程 MyThread myThread = new MyThread();
      myThread.start();
      public static native Thread currentThread(); 获取当前线程实例对象 Thread thread = Thread.currentThread();
      public static native void yield(); 让出CPU时间片 Thread.yield();
      public static native void sleep(long millis); 睡眠指定时间 Thread.sleep(1L);
      public void interrupt() {……} 中断线程 MyThread myThread = new MyThread();
      myThread.interrupt();
      public static boolean interrupted() {……} 判断线程是否已中断 MyThread myThread = new MyThread();
      boolean interrupted = myThread.isInterrupted();
      public final native boolean isAlive(); 判断线程是否是存活状态 MyThread myThread = new MyThread();
      boolean alive = myThread.isAlive();
      public final String getName() {……} 获取线程名称 MyThread myThread = new MyThread();
      String name = myThread.getName();
      public State getState() {……} 获取线程状态 MyThread myThread = new MyThread();
      Thread.State state = myThread.getState();
      public long getId() {……} 获取线程ID MyThread myThread = new MyThread();
      long id = myThread.getId();
      public final void join() {……} 等待其他线程执行完再执行 MyThread myThread = new MyThread();
      myThread.join();

      以上就是Java基础夯实之线程问题全面解析的详细内容,更多关于Java线程的资料请关注其它相关文章!

      声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。