多线程学习笔记

一、线程

1、定义线程有两种方式:扩展Thread类和实现Runnable接口。使用start方法启动线程。

2、线程状态:创建(new),就绪(Runnable),运行(Running),阻塞(Blocked)和终止(dead),状态转换如下图。

3、sleep和wait的区别

 1)sleep是Thread类的方法,wait是Object类的方法
 2)Thread.sleep不会导致锁行为的改变, 如果当前线程是拥有锁的, 那么Thread.sleep不会让线程释放锁
 3)Thread.sleep和Object.wait都会暂停当前的线程. OS会将执行时间分配给其它线程. 区别是, 调用wait后, 需要别的线程执行notify/notifyAll才能够重新获得CPU执行时间。

4、sleep和yield方法区别
 1) sleep方法给其他线程运行机会时不会考虑线程的优先级,因此低优先级的线程也有机会运行。yield方法只会给相同优先级或更高优先级的线程以运行的机会
  2)线程执行sleep方法后转入阻塞状态,而yield方法执行后转入就绪(ready)状态
  3)sleep方法声明抛出InterruptException,而yield方法没有声明任何异常
  4)  sleep方法比yield方法具有更好的移植性

5、常用方法

start(): 使线程开始执行;java虚拟机调用该线程的run方法
run():运行业务方法
setName():改变线程名称,使之与参数name相同
setPriority():更改线程的优先级
setDaemon(boolean):将改线程标记为守护线程或用户线程;守护线程是在后台执行并且不会阻止JVM终止的线程,当没有用户线程在运行的时候,JVM关闭程序并且退出。
join(long milliesec):等待线程终止的时间最长为millis毫秒,当前线程A等待thread线程终止之后才从thread.join()返回。
interrupt():中断线程
isAlive():测试线程是否处于活动状态
yield():暂停当前正在执行的线程对象,并执行其他线程,放弃时间不确定,不会让出锁
sleep():指定的毫秒内让正在执行的线程休眠
currentThread():返回对当前正在执行的线程对象的引用

6、并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。

     并发:通过cpu调度算法,让用户看上去是同步执行。
       悲观锁
        synchronized:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作
       乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。如CAS atomic;缺点是不能解决脏读问题,会出现ABA问题,添加版本号来避免此问题

二、线程间通信方式

1、管道:半双工,数据只能单向流动,有血缘关系的进程间流动

2、有名管道: 允许无血缘关系的进程间流动

3、信号量:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。是一种同步手段

4、消息队列:由消息组成的链表,存放在内核中,并由消息队列标识符标识

5、信号: 用于通知接收进程某一事件已经发生。

6、共享内存

7、套接字socket
    长连接:整个通讯过程,客户端和服务端只用一个Socket对象,长期保持Socket的连接
    短连接:每次请求,都新建一个Socket,处理完一个请求就直接关闭掉Socket

三、线程间通信机制

有锁机制、信号量机制和信号机制

锁机制:
    互斥锁: 提供了以排它方式阻止数据结构被并发修改的方法
    读写锁:允许多个线程同时读共享数据,而对写操作互斥
    条件变量:可以以原子阻塞进程,直到某个特定条件为真为止

信号量机制:包括无名线程信号量与有名线程信号量

四、线程安全的实现方法

1、互斥同步:临界区、互斥量、信号量

2、非阻塞同步: 硬件指令集

3、ReentrantLock:可重入锁
    1)等待可中断:持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待,改为处理其他事情
    2)可实现公平锁:公平锁是指多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁;
    3)锁可以绑定多个条件
    4)默认非公平的通过带布尔值的构造函数要求使用公平锁

4、synchronized
    重量级操作,状态切换需要耗费很多的处理器时间。确实必要才使用,虚拟机本身对它的优化:通知操作系统阻塞线程之前加入一段自旋等待过程,避免频繁的切入到核心状态之中。是非公平的。

5、如何确保线程安全

1)使用原子类
2)实现并发锁
3)使用volitale关键字
4)使用不变类和线程安全类

五、Web并发访问问题

1、Servlet线程安全问题:单例模式,存在线程安全问题
       1)在Servlet中不要定义类变量或实例变量
       2)为操作该变量的所有方法加synchronized修饰符,进行同步控制

2、Spring线程安全问题:优点是我们不用每次创建Controller, 减少了对象创建和垃圾收集的时间,缺点是并发访问时会出现安全问题。
    1)避免在Controller中定义类变量和实例变量
    2)在Controller中使用ThreadLocal变量
    3)声明scope="prototype",每次创建新的Controller

3、SpringMVC线程安全问题
    1)对操作共享变量的所有方法进行同步控制
    2)同步共享变量如:Collections.synchronizedMap()
    3)使用同步对象

六、线程池
    1、为什么使用线程池
        1)创建/销毁线程伴随着系统开销,过于频繁,影响处理效率
        2)线程并发数量过多,抢占系统资源导致阻塞
        3)对线程进行一些简单的管理(延时,定时循环等)
    2、优点
        1)降低资源消耗
        2)提高响应速度
        3)提高线程的可管理性
    3、java.uitl.concurrent.ThreadPoolExecutor
        1)corePoolSize:核心线程数最大值
        2)maximunPoolSize:线程池最大线程数(核心线程 + 非核心线程)
        3)keepAliveTime:对非核心线程没有任务执行时最多保持多久时间会终止
        4)workQueue:一个阻塞队列,用来存储等待执行的任务
            ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;
            LinkedBlockQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE;
            SynchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务
        5)threadFactory:线程工厂
        6)handler:表示当拒绝处理任务时的策略
            AbortPolicy:丢弃任务并抛出异常
            DiscardPolicy:丢弃任务不抛出异常
            DiscardOldestPolicy:丢弃队列最前面的任务,重新尝试执行任务
            由调用线程处理该任务
        7)策略
            线程数量未达到corePoolSize,则新建一个核心线程执行任务
            线程数量达到了corePoolSize,则进入队列等待
            队列已满,新建非核心线程执行任务
            队列已满,总线程达到了maximumPoolSize则抛出RejectedExcutionHandler异常
    4、线程池分类
        1)fixThreadPool:正规线程
            有指定的线程数的线程池,有核心的线程,里面有固定的线程数量,响应的速度快
            没有超时机制,队列大小没有限制,除非线程池关闭了核心线程才会回收
        2)cacheThreadPool:缓存线程池
            只有非核心线程,最大线程数很大有超时回收机制
            没有考虑到系统的实际内存大小
        3)singleThreadPool:单线程线程池
            只有一个核心线程,不处理并发的操作,不会被回收
        4)ScheduledThreadPool
            有延迟执行和周期重复执行的线程池,核心线程池固定,非核心线程池不限,闲置时会回收。
    5、可能出现的危险
        死锁、资源不足、并发错误、线程泄漏、请求过载、

    6、核心线程
        核心线程默认情况下会一直存活在线程池中,即使这个核心线程啥也不干(闲置状态)。
        线程池新建线程的时候,如果当前线程总数小于corePoolSize,则新建的是核心线程,如果超过corePoolSize,则新建的是非核心线程;allowCoreThreadTimeOut设置此项可以让核心线程闲置状态下回收
    7、添加任务
        ThreadPoolExecutor.execute(Runnable command)
    8、线程池的关闭
        shutdown():不会立即关闭,是等待所有任务缓存队列中的任务都执行完后才终止,但也不会接受新的线程
        shutdownNow():立即终止线程池,尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值