并发多线程

1,什么是多线程

多线程就是在同一时间干多件事

  • 并行:多个流水线同时进行(一个流水线一个核心(线长))
  • 并发:一个核心(线长)管理多个线程,(流水线)进行快速交替工作

        快速交替:线长去一号线干活五分钟,然后去2号线干6分钟,再去3号线干四分钟

2,多线程的好处

1- 例如:空调制作

非多线程:先制造空调本体,再制造空调遥控器,按顺序执行

多线程:在制造空调本体的同时,再开一条流水线做空调遥控器,两条流水线一起执行

2- 线程可以认为是一个轻量级的进程,线程的创建,销毁性能开销更小

3,多线程的弊端

如果并发的线程数量很多,并且每个线程执行的任务很短,这样就会频繁的创造和销毁线程,会大大降低系统的效率,如果大量线程在执行,会涉及到线程上下文的切换,会极大消耗cpu运算资源

4,如何创建线程

  • 继承Thread
  • 实现Runnable接口
  • 使用 Callable接口(可以使用CompletableFutrue)

5,线程安全

多线程在对共享数据操作的时候,可能会导致数据错乱,这就是线程安全

如何判断当前程序是否存在线程安全

  • 是否存在多线程环境
  • 在多线程环境下是否存在共享变量
  • 在多线程环境下是否存在对共享变量 “ 写 ” 操作

6,线程的生命周期

  • 新建状态(New):新创建了一个线程对象
  • 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权限
  • 运行状态(Running):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态
  • 死亡状态(Dead):线程执行完了或者因异常退出了run方法,该线程结束生命周期

 7,tait和sleep的区别

共同点:

  • wait(),wait(long)和sleep(long)的效果都是让当前线程放弃CPU的使用权,进入阻塞状态

不同点:

  • 方法归属不同
    • sleep(long)是 Thread 的静态方法
    • wait(),wait(long)都是 Object 的成员方法,每个对象都有
  • 醒来时机不同
    • 执行sleep(long)和wait(long)的线程都会在等待相应毫秒后醒来
    • wait(long)和wait()还可以被notify唤醒,wait()如果不换形就一直等待下去
    • 它们都可以被打断唤醒
  • 锁特性不同
    • wait 方法的调用必须先获取wait对象的锁,而sleep则无此限制
    • wait方法执行后会释放对象锁,允许其他线程获得该对象锁(我放弃cpu,但你们还可以用)
    • 而sleep 如果在synchronized代码块中执行,并不会释放对象锁(我放弃cpu,你们也用不了)

8,valatile的作用和原理

JMM内存模型

JMM让java程序与硬件指令进行了隔离

  •  由于JVM运行程序的实体是线程,创建每个线程时,java内存模型会为其创建一个工作内存(一般称为栈),工作内存是每个线程的私有数量区域
  • java内存模型规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问
  • 但线程对变量的操作(读取,赋值等)必须在工作内存中进行。因此首先要将变量从主内存拷贝到自己的工作内存,然后对变量进行操作,操作完成后再将变量写回主内存中

9,Java并发编程要解决的三个问题(三大特征)

原子性

一个线程在cpu中操作不可指定,也不可中断,要么执行完成,要么不执行

内存可见性

默认情况下,当一个线程修改内存中某个变量时,主内存值发生了变化,并不会主动通知其他线程,即其他线程并不可见

有序性

程序执行的顺序按照代码的先后顺序执行

10,为什么用线程池 线程池参数

  • 降低资源消耗;提高线程利用率,降低创建和销毁线程的消耗
  • 提高响应速度;任务来了,直接有线程可用可执行,而不是先创建线程,再执行
  • 提高线程的可管理性;线程是稀缺资源,使用线程池可以统一分配调优监控
/*
corePoolSize 代表核心线程数,也就是正常情况下创建工作的线程数,这些线程创建后并不会 
消除,而是一种常驻线程 

maxinumPoolSize 代表的是最大线程数,它与核心线程数相对应,表示最大允许被创建的线程 
数,比如当前任务较多,将核心线程数都用完了,还无法满足需求时,此时就会创建新的线程,但 
是线程池内线程总数不会超过最大线程数 

keepAliveTime 、 unit 表示超出核心线程数之外的线程的空闲存活时间,也就是核心线程不会 
消除,但是超出核心线程数的部分线程如果空闲一定的时间则会被消除,我们可以通过keepAliveTime 、
unit 表示超出核心线程数之外的线程的空闲存活时间,
也就是核心线程不会 setKeepAliveTime 来设置空闲时间 


workQueue 用来存放待执行的任务,假设我们现在核心线程都已被使用,还有任务进来则全部放 
入队列,直到整个队列被放满但任务还再持续进入则会开始创建新的线程 

ThreadFactory 实际上是一个线程工厂,用来生产线程执行任务。我们可以选择使用默认的创建 
工厂,产生的线程都在同一个组内,拥有相同的优先级,且都不是守护线程。当然我们也可以选择 
自定义线程工厂,一般我们会根据业务来制定不同的线程工厂 

Handler 任务拒绝策略,有两种情况,第一种是当我们调用 shutdown 等方法关闭线程池后,这 
时候即使线程池内部还有没执行完的任务正在执行,但是由于线程池已经关闭,我们再继续想线程 
池提交任务就会遭到拒绝。另一种情况就是当达到最大线程数,线程池已经没有能力继续处理新提 
交的任务时,这是也就拒绝


*/ 
  public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

java中常见的几种线程池

// 创建一个可缓存的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程
//若无可回收,则新建线程
Executors.newCachedThreadPool();

//创建一个定长线程池,可控制线程最大并发数,超出的线程会再队列中等待
Executors.newFixedThreadPool();

//创建一个定长线程池,支持定时及周期性任务执行
Executors.newScheduledThreadPool(10);//核心线程数

//创建一个单线程化的线程池,它只会唯一的工作线程来执行任务
//保证所有任务按照指定顺序(FIFO , LIFO , 优先级)执行
Executors.newSingleThreadExecutor();

 11,synchronized

synchronized 锁释放时机

  • 当前线程的同步方法,代码块执行结束的时候释放
    • 正常结束
    • 异常结束出现未处理的error 或者 exception 导致异常结束的时候释放
  • 程序执行了同步对象wait方法,当前线程暂停,释放锁(sleep不会释放锁)

12,synchronized 和 ReentrantLock的区别

  • synchronized 是一个关键字,ReetrantLock是一个类
  • synchronized的底层是JVM层面的锁(底层由C++编写实现),ReentranLock是API层面的锁(java内部的一个类对象)
  • synchronized会自动的加锁与释放锁,ReentrantLock需要程序员手动加锁与释放锁
  • synchronized是非公平锁,ReentrantLock可以选择公平锁或非公平锁

        注: 假设多个线程都要获取锁对象,满足先等待的线程先获得锁则是公平锁,否则是非公平锁

  • synchronized锁的是对象,锁信息保存在对象头中,ReebntrantLock通过代码中int类型的starte表示来标识锁的状态
  • sychronized底层有⼀个锁升级的过程(访问对象线程数由少到多,竞争由不激烈到激烈,底层会通过一种锁升级机制 无锁->偏向锁->轻量级锁->重量级锁,保证性能) ,会使用自旋 线程频繁等待唤醒会浪费性能,特别是锁的获取也许只需要很短的时间 ,不限于等待,直接执行简单代码while(true)执行完抢锁 来优化性能
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值