前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >多线程

多线程

原创
作者头像
喜乐
修改2022-03-14 11:57:34
6500
修改2022-03-14 11:57:34
举报
文章被收录于专栏:JAVA_喜乐JAVA_喜乐

1. 线程

1.1 线程的概念

线程是操作系统调度的最小单元,也叫轻量级进程。它被包含在进程之中,是进程中的实际运作单位。同一进程可以创建多个线程,每个进程都有自己独立的一块内存空间。并且能够访问共享的内存变量。

1.2 线程和进程的区别

进程是资源分配的最小单位,线程是CPU调度的最小单位

大白话说下区别:

  • 线程在进程下行进(单纯的车厢无法运行)
  • 一个进程可以包含多个线程(一辆火车可以有多个车厢)
  • 不同进程间数据很难共享(一辆火车上的乘客很难换到另外一辆火车,比如站点换乘)
  • 同一进程下不同线程间数据很易共享(A车厢换到B车厢很容易)
  • 进程要比线程消耗更多的计算机资源(采用多列火车相比多个车厢更耗资源)
  • 进程间不会相互影响,一个线程挂掉将导致整个进程挂掉(一列火车不会影响到另外一列火车,但是如果一列火车上中间的一节车厢着火了,将影响到所有车厢)
  • 进程可以拓展到多机,进程最多适合多核(不同火车可以开在多个轨道上,同一火车的车厢不能在行进的不同的轨道上)
  • 进程使用的内存地址可以上锁,即一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。(比如火车上的洗手间)-"互斥锁"
  • 进程使用的内存地址可以限定使用量(比如火车上的餐厅,最多只允许多少人进入,如果满了需要在门口等,等有人出来了才能进去)-“信号量”

1.3 线程的几种创建方式

  • 继承Thread类
代码语言:javascript
复制
public class ThreadCreateOne {
    public static void main(String[] args) {
        ThreadOne thread = new ThreadOne();
        thread.start();
    }
}

class ThreadOne extends Thread {
    public void run() {
        System.out.println("线程已经启动!");
    }
}
  • 实现Runnable接口
代码语言:javascript
复制
public class ThreadCteateTwo {
    public static void main(String[] args) {
        Thread thread = new Thread(new ThreadTwo());
        thread.start();
    }
}

class ThreadTwo implements Runnable{
    @Override
    public void run() {
        System.out.println("线程已经启动!");
    }
}
  • 实现Callable接口
代码语言:javascript
复制
public class ThreadCreateThree {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new ThreadThree());
        new Thread(futureTask).start();
        Integer integer = futureTask.get();
        System.out.println("线程返回结果:" + integer);
    }
}

class ThreadThree implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        System.out.println("线程已经执行!");
        return 1;
    }
}
  • 从线程池中获取

1.4 线程的几种状态

  • NEW:刚刚创建,没做任何操作
代码语言:javascript
复制
  public static void main(String[] args) {
       Thread thread = new Thread();
       System.out.println("当前线程状态:"+thread.getState());
   }
  • RUNNABLE:调用run,可以执行,但不代表一定在执行(RUNNING,READY)
代码语言:javascript
复制
    public static void main(String[] args) {
        Thread thread = new Thread();
        thread.start();
        System.out.println("当前线程状态:"+thread.getState());
    }
  • BLOCKED:抢不到锁
代码语言:javascript
复制
public class ThreadStatus3 {
    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (ThreadStatus3.class){
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (ThreadStatus3.class) {

                }
            }
        });
        thread.start();
        Thread.sleep(1000);
        System.out.println("当前线程状态:"+thread.getState());
    }
}
  • WAITING:等待
代码语言:javascript
复制
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                LockSupport.park();
            }
        });
        thread.start();
        Thread.sleep(500);
        System.out.println("当前线程状态:"+thread.getState());
        LockSupport.unpark(thread);
        Thread.sleep(500);
        System.out.println("当前线程状态:"+thread.getState());
    }
  • TIMED_WAITING
代码语言:javascript
复制
    public static void main(String[] args) throws InterruptedException {
        Thread thread3 = new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread3.start();
        Thread.sleep(500);
        System.out.println("当前线程状态:"+thread3.getState());
    }
  • TERMINATED
代码语言:javascript
复制
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread();
        thread.start();
        Thread.sleep(1000);
        System.out.println("当前线程状态:"+thread.getState());
    }

2. 线程池

2.1 线程池的概念

根据上述的状态,普通线程执行完,就会进入TERMINATED销毁掉,而线程池就是创建一个缓冲池存放线程,执

行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态【阻塞状态】,等候下次任务来临,这使得线程池比手动

创建线程有着更多的优势:

  • 降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗;
  • 提高系统响应速度,当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执行;
  • 方便线程并发数的管控。因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM
  • 节省cpu切换线程的时间成本(需要保持当前执行线程的现场,并恢复要执行线程的现场)。
  • 提供更强大的功能,延时定时线程池。(Timer vs ScheduledThreadPoolExecutor

常用的线程池列举:

  1. 最常用的是ThreadPoolExecutor
  2. 调度用ScheduledThreadPoolExecutor
  3. 任务拆分合并用ForkJoinPool
  4. Executors是工具类,协助你创建线程池的

2.2 线程池工作机制

在线程池的编程模式下,任务是提交给整个线程池,而不是直接提交给某个线程,线程池在拿到任务后,就在内部

协调空闲的线程,如果有,则将任务交给某个空闲的线程。一个线程同时只能执行一个任务,但可以同时向一个线

程池提交多个任务【解释:假设线程池中的A线程接到任务后,会首先处理接到的任务,处理完成后,会先去线程池

中查看是否还有未处理的任务,如果有则会获取任务继续执行,并不会直接进入空闲状态】。

2.3 线程池的工作状态

  • RUNNING
  1. 状态说明:线程池处在RUNNING状态时,能够接收新任务,以及对已添加的任务进行处理。
  2. 状态切换:线程池的初始化状态是RUNNING。换句话说,线程池被一旦被创建,就处于RUNNING状态!
  • SHUTDOWN
  1. 状态说明:线程池处在SHUTDOWN状态时,不接收新任务,但能处理已添加的任务。
  2. 状态切换:调用线程池的shutdown()接口时,线程池由RUNNING -> SHUTDOWN。
  • STOP
  1. 状态说明:线程池处在STOP状态时,不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。
  2. 状态切换:调用线程池的shutdownNow()接口时,线程池由(RUNNING or SHUTDOWN ) -> STOP。
  • TIDYING
  1. 状态说明:当所有的任务已终止,ctl记录的"任务数量"为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会执行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若用户想在线程池变为TIDYING时,进行相应的处理;可以通过重载terminated()函数来实现。
  2. 状态切换:当线程池在SHUTDOWN状态下,阻塞队列为空并且线程池中执行的任务也为空时,就会由 SHUTDOWN -> TIDYING。
  3. 当线程池在STOP状态下,线程池中执行的任务为空时,就会由STOP -> TIDYING。
  • TERMINATED
  1. 状态说明:线程池彻底终止,就变成TERMINATED状态。
  2. 状态切换:线程池处在TIDYING状态时,执行完terminated()之后,就会由 TIDYING -> TERMINATED。

2.4 线程任务说明

  1. 添加任务,如果线程池中线程数没达到coreSize,直接创建新线程执行
  2. 达到core,放入queue
  3. queue已满,未达到maxSize继续创建线程
  4. 达到maxSize,根据reject策略处理
  5. 超时后,线程被释放,下降到coreSize·
代码语言:javascript
复制
public class ThreadPoolDemo1 {
    private static final int CORE_SIZE = 2;
    private static final int MAX_SIZE = 2;
    private static final int KEEP_ALIVE_TIME = 1;
    private static final int QUEUE = 1;
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(CORE_SIZE,MAX_SIZE, KEEP_ALIVE_TIME,TimeUnit.SECONDS,new LinkedBlockingDeque<>(QUEUE));
        for (int i=0 ;i<5;i++){
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                        System.out.println(Thread.currentThread().getName()+"线程已经执行");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }
}

2.5 线程关键方法分析

  • excute
  • addWorker

  • getTask

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 线程
    • 1.1 线程的概念
      • 1.2 线程和进程的区别
        • 1.3 线程的几种创建方式
          • 1.4 线程的几种状态
          • 2. 线程池
            • 2.1 线程池的概念
              • 2.2 线程池工作机制
                • 2.3 线程池的工作状态
                  • 2.4 线程任务说明
                    • 2.5 线程关键方法分析
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
                    http://www.vxiaotou.com