0


线程的实现方式总结

提示:阅读本篇文章前,请先了解操作系统中线程和进程的基本概念。

线程基本概念本文会有所提及,操作系统和进程请参考我的这两篇笔记 https://note.youdao.com/s/ag3ipekEhttps://note.youdao.com/s/ag3ipekE

https://note.youdao.com/s/BFTOv61yhttps://note.youdao.com/s/BFTOv61y

前言:

在系统层面,为了减少操作的耗时,提高程序并行操作效率以及CPU的利用率,我们引入了多线程的技术概念。、

本文将从线程的基本概念讲起,详细介绍创建多线程的四种方式。

一、多线程的基础知识

1.1 什么是线程

    线程是进程内部的一个可执行单元,是可以完成一个独立任务的顺序控制流程,如果在一个进程中同时运行多个线程,用来完成不同的工作,则称之为多线程。

1.2 何时需要多线程

    (1)程序需要同时执行两个或两个以上任务时。

    (2)程序需要执行一些需要等待的任务时,比如用户注册,文件读写。

    (3)需要后台执行程序时。

1.3 多线程的优缺点

    优点:
  • 能适当的提高程序的执行效率

  • 能适当提高资源利用率(cpu、内存利用率)

      缺点:
    
  • 开启线程需要占用一定的内存空间,(默认情况下,主线程1M,子线程512KB),如果开启大量的线程,会占用大量的内存空间,降低程序的性能。

  • 线程越多,cpu在调度线程上的开销就越大。

  • 程序设计更加复杂:比如线程之间的通讯、多线程的数据共享

1.4 多线程的物种状态

  1. NEW:新建状态。当一个线程被创建后,启动之前,就处于该状态。
  2. RUNNABLE:可运行状态。当一个线程正在执行任务,就处于该状态。
  3. WAITING:无限等待状态。一个线程获取Lock锁对象,失败,就处于该状态。
  4. TIMED_WAITING:计时等待状态。当一个线程正在执行sleep方法的时候,就处于该状态。
  5. BLOCKED:阻塞状态。一个线程获取synchronized(代码块、方法)锁对象,失败,就处于该状态。
  6. TERMINATED:消亡状态。当线程把任务执行结束后,就处于该状态。

其中NEW状态和TERMINATED状态只会出现一次。

二、线程的实现方式

创建子线程就是:创建Thread类型的对象,并启动执行。

2.1 继承Thread类

** Thread类:**
所属包:java.lang;
构造方法:
public Thread();
public Thread(Runnable target);
public Thread(Runnable target,String name);
** 静态方法:**
static Thread currentThread();//获取当前线程,哪个线程执行该方法,就获取哪个线程
成员方法:
void start();//只能调用一次,不能调用多次
void run();//线程启动以后,会执行run方法中的代码
String getName();//获取线程的名称
void setName(String name);//设置线程的名称

继承Thread类创建线程的步骤如下:

  1. 创建一个继承于Thread类的子类。
  2. 重写Thread类的run方法–>将此线程执行的操作声明在run()中。
  3. 创建子类对象。
  4. 通过子类对象调用start()方法。

** 创建Thread类的对象,重写run()方法的代码如下:**

public class Test01Thread {
    public static void main(String[] args) {
        //以匿名内部类的方式创建Thread类型的对象,创建线程
        Thread t = new Thread() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                System.out.println(name);
            }
        };
        t.start();//启动线程
        
    };

}

2.2 实现Runnable接口

  **  Runnable接口:**

            **Runnable比Thread类所具有的优势:**
               1.可以避免java中的单继承的局限性(java是单继承多级继承,而实现是多实现)
               2.任务和线程分离,实现了解耦合
               3.线程池只能传入Runnable或者Callable类型的对象,不能使用继承的方式

** 实现Runnable接口创建线程的步骤如下:**

  1. 创建一个实现了Runnable接口的类
  2. 实现Runnable接口中的方法。
  3. 创建实现类的对象。
  4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象。
  5. 通过Thread类的对象调用start()方法。

** 实现Runnable接口创建线程的代码如下:**

public class Test02Runnable {
    public static void main(String[] args) {
        //采用匿名内部类的方式创建Runnable类型的对象
        Runnable r = new Runnable() {
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                System.out.println(name);
            }
        };
        
        //创建线程
        Thread t = new Thread(r,"线程1");
        t.start();
    }

}

2.3 实现Callable接口

     **callable接口:**

实现Callable接口的步骤如下:

  1. 创建子类实现callable的实现类。
  2. 实现call方法,将此线程需要执行的操作声明在call方法中。
  3. 创建Callable接口对象
  4. 将此Callable实现类的对象作为参数传递到FutureTask构造器中,创建FutureTask对象。
  5. 将FutureTask类的序传递到Thread类的构造器中,创建Thread类的对象,通过该对象启动线程
  6. 可以获取Callable实现类的call方法的返回值。(可选,需要返回值就get,不需要就不get)
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public class Test03Callable {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        //通过匿名内部类的方式创建Callable类型的对象
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println(Thread.currentThread().getName());
                return "存在返回值";
            }
        }; 
        
        //创建FutureTask对象接受callable返回值结果
        FutureTask<String> ft=new FutureTask(callable);
        
        //创建线程
        Thread t=new Thread(ft);
        
        //启动线程
        t.start();
        //获取线程的返回结果
        String str = ft.get();
        
        System.out.println(str);//测试Callable的返回值
    }

}

2.4 线程池

   ** 线程池创建线程:**
      **优点:**
          1.降低资源消耗(减少了频繁的创建和销毁线程)。
               线程池中的线程可以提前创建,而且只需完任务以后可以不销毁
          2.提高响应速度。 线程池中的线程可以提前创建线程。
          3.提高线程的可管理性。(任务很多,而且每个任务需要消耗的时间比较长)
           创建一个线程大约需要消耗1M的空间。

       **语法:**
           **Executors类**
               static ExecutorService newFixedThreadPool(int c);//参数是线程的数量

           **ExecutorService接口:**
               void execute(Runnable r);
               Future<?> submit(Runnable r);//如果线程执行完任务后又返回值,则可以处理返回的结果
               <T> Future<T> submit(Callable<T> c);
               void shutdown();//关闭线程池

          ** Future<T>接口**
               T get();//必须等待子线程任务执行结束后,才可以获取到返回结果。

** 实现Runnable接口,利用线程池创建线程。 **

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test04Executors {
    public static void main(String[] args) {
        //创建固定线程池对象,2为创建两个线程.
        ExecutorService threadPool = Executors.newFixedThreadPool(2);
        
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        };
        
        //执行任务
        threadPool.execute(r);
        
        //关闭
        threadPool.shutdown();
    }

}

实现Callable接口,利用线程池创建线程,并获取返回值。

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Test05ExecutorsCall {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        //创建线程池对象
        ExecutorService threadPool = Executors.newFixedThreadPool(1);
        
        //通过匿名内部类的方式创建Callable类型的对象
        Callable<String> callable = new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println(Thread.currentThread().getName());
                Thread.sleep(10000);
                return "有返回值";
            }
        }; 
        
        //执行任务
        Future<String> future = threadPool.submit(callable);
        //获取线程的返回结果。
        String str = future.get();
        
        System.out.println(str);//测试Callable的返回值
        
        //关闭
        threadPool.shutdown();
    }

}

最后,感谢大家的持续支持!!!

学而时习之,才能有所进步。


本文转载自: https://blog.csdn.net/m0_46420244/article/details/125119246
版权归原作者 飘飘~ 所有, 如有侵权,请联系我们删除。

“线程的实现方式总结”的评论:

还没有评论