Java多线程

线程

线程是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运用单位(简单理解:应用软件中相互独立,可以同时运行的功能)

并发:在同一时刻,有多个指令在单个CPU上交替执行

并行:在同一时刻,有多个指令在多个CPU上同时执行

多线程的实现方式

  1. 继承Thread类的方式实现
    1. 继承Thread类
    2. 重写Thread类中的run方法
  2. 实现Runnable接口的方式进行实现
    1. 自己定义一个类实现Runnable接口
    2. 重写里面的run方法
    3. 创建自己的类的对象
    4. 创建一个Thread类的对象,并开启线程
  3. 利用Callable接口和Future接口方式实现(特点:可以获取多线程运行的结果)
    1. 创建一个类MyCallable实现Callable接口
    2. 重写call(是有返回值的,表示多线程运行的结果)
    3. 创建MyCallable的对象(表示多线程要执行的任务)
    4. 创建FutureTasak的对象(作用管理多线程运行的结果)
    5. 创建Thread类的对象,并启动(表示线程)
多线程三种实现方式的对比
优点缺点
继承Thread类编程比较简单,可以直接使用Thread类中的方法扩展性较差,不能再继承其他类
实现Ruunable接口扩展性强,实现该接口的同时还可以继承其他类编程相对复杂,不能直接使用Thread类中的方法
实现Callable接口

常见的成员方法

方法名称说明
String getName()返回此线程的名称
void setName(String name)设置线程的名字(构造方法也可以设置名字)
static Thread currentThread()获取当前线程的对象
static void sleep(long time)让线程休眠指定的时间,单位为毫秒
setPriority(int newPriority)设置线程的优先级
final int getPriority()获取线程的优先级
final void setDaemon(boolean on)设置为守护线程
public static void yield()出让线程/礼让线程
public static void join()插入线程/插队线程

名字:

  1. 如果没有给线程设置名字,线程也是有默认的名字的(格式: Thread-X(X序号,从0开始的))
  2. 如果我们要给线程起名字,可以用set方法,也可以构造方法设置

sleep:

  1. 那条线程执行到这个方法,那么那条线程就会在这里停留对应的时间
  2. 方法的参数:表示睡眠的时间,单位毫秒
  3. 当时间到了之后,线程会自动的醒来,继续执行下面的其他代码

守护线程:当其他非守护线程执行完毕之后,守护线程也没有存在的必要了

线程的生命周期

线程的安全问题 

同步代码块

把操作共享数据的代码锁起来

格式:
synchronized (锁) {
    操作共享数据的代码
}

特点1:锁默认打开,有一个线程进去的了,锁自动关闭

特点2:里面的代码全部执行完毕,线程出来,锁自动打开 

锁对象:一定要是唯一的

同步方法

就是把synchronized关键字加到方法上

格式:
修饰符 synchronized 返回值类型 方法名(方法参数) {...}

特点1:同步方法是锁住方法里面所有的代码

特点2:锁对象不能自己指定(非静态:this, 静态:当前类的字节码文件对象) 

书写套路:

        1.循环

        2.同步代码块        

        3.判断共享数据是否到了末尾,如果到了末尾

        4.判断共享数据是否到了末尾,如果没有到末尾

Lock锁

        Lock中提供了获得锁和释放锁的方法

        void lock():获得锁

        void unlock():释放锁

        Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化

        ReentrantLock的构造方法

        `ReentrantLock():创建一个 ReentrantLock的实例


生产者和消费者(等待唤醒机制)

消费者:

  1. 判断桌子上是否有食物
  2. 如果没有就等待
  3. 如果有就开吃
  4. 吃完之后,唤醒厨师继续做

生产者

  1. 判断桌子上是否有食物
  2. 有:等待
  3. 没有:制作食物
  4. 把食物放在桌子上
  5. 叫醒等待的消费者开吃
生产者和消费者常见方法
方法名称说明
void wait()当前线程等待,直到被其他线程唤醒
void notify()随机唤醒单个线程
void notifyAll()唤醒所有线程

阻塞队列的继承结构

线程池

主要原理:

  1. 创建一个池子,池子中是空的
  2. 提交任务,池子会创建新的线程对象,任务执行完毕,线程归还给池子下回再次提交任务时,不需要创建新的线程,直接复用已有的线程即可
  3. 但是如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待

线程池代码实现

  1. 创建线程池
    1. Executors:线程池的工具类通过调用方法返回不同类型的线程池对象
      方法名称说明
      public static ExecuroeService newCachedThreadPool()创建一个没有上线的线程池
      public static ExecutorService newFixedThreadPool(int nThreads)创建有上限的线程池

  2. 提交任务
  3. 所有的任务全部执行完毕,关闭线程池 

自定义线程池

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor

(核心线程数量, 最大线程数, 空闲线程最大存活时间, 时间单位, 任务队列, 创建线程工厂, 任务的拒绝策略)

参数一:核心线程数量                                不能小于0

参数二:最大线程数                                    不能小于等于0,最大数量 >= 核心线程数量

参数三:空闲线程最大存活时间                   不能小于0

参数四: 时间单位                                         用TimeUnit指定

参数五:任务队列                                           不能为null

参数六:创建线程工厂                                     不能为null

参数七:任务的拒绝策略                                  不能为null

线程池多大合适

项目类型:

  1. CPU密集型运算(计算比较多.读取数据比较少) :   最大并行数 (可用  Runtime.getRuntime().availableProcessors()方法获取)+ 1
  2. I / O密集型运算(读取本地文件较多或读取数据库比较多):   最大并行数 * 期望CPU利用率 * 总时间(CPU计算时间+等待时间)  /  (CPU计算时间)

  • 28
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值