多线程相关基础知识

进程与线程区别:
1、进程的创建与销毁大于线程;
2、进程是操作系统分配资源的基本单位,线程是操作系统调度的基本单位;
3、一个进程内可以有多个线程,一条线程只能存于一个进程内;
4、进程之间资源分配是独立的,线程之间共享进程中的资源;

概念:
临界区:各个线程共享的资源,但每次只能有一条线程使用;
死锁:线程之间互相等待对方的占用的资源,以至于无法进行下一步工作(线程状态不变);
活锁:线程之间互相谦让,以至于无法进行下一步工作(线程状态会变);
饥饿:线程无法获得所需的资源;

并发级别:
阻塞:在某线程释放资源之前,其它线程无法继续执行;(悲观策略,认为冲突一定会产生)
无饥饿:各条线程都有机会执行,先来后到、公平锁;
无障碍:不会阻塞,但共享数据发生了冲突,则会把相关线程所做修改回滚;(乐观策略,认为冲突不一定会产生)
无锁:所有线程都可以对临界区访问,会有一个无穷循环,线程会一直访问临界区,直到没有冲突,修改成功;
无等待:不会被锁定,有限步完成,比如先读数据,在适时的时候写回;

达到线程安全的三条性质:
原子性:一个操作是不可中断的,要么全部执行成功要么全部执行失败,有着“同生共死”的感觉;
可见性:指当一个线程修改了共享变量后,其他线程能够立即得知这个修改;
有序性:为了提高性能,编译器和处理器常常会对指令进行重排序,但在单线程里最终执行结果不变;

两个核心:
JMM;
Happen-Before规则:Java虚拟机和执行系统会对指令重排序,但也是有一定规则不能违背的;

 

 

 线程实现:

1、继承Thread;
2、实现Runnable接口;
3、用Future、Callable,带返回值地创建;
4、使用线程池创建;

线程生命周期:
新建、就绪、运行、阻塞、死亡;(其中就绪、运行、阻塞可以相互转化)

终止线程和线程中断:
终止:线程对象.stop() 直接停止线程;
中断:线程对象.interrupt() 标记中断,
     当前线程.isInterrupted() 判断线程是否有中断标记,
     当前线程.interrupted() 判断线程是否有中断标记,有则清除标记;

 

 

 关键字:

Object中的:
等待和通知:wait(交出锁)、notify/notifyAll;
Thread中的:
join(等待该线程结束)、yield(当前线程让出CPU,重新去竞争)、sleep(暂停,不交出锁);

线程其它相关:
1、线程组:对线程组操作,相当于对线程组里的所有线程操作;
2、守护线程:用户线程结束后,守护线程就会结束;
3、线程优先级:高优先级有更大的概率获取资源;

锁:
1、synchronized:Java的原生锁,可以用在类、方法、代码块、变量、对象上;
2、重入锁(ReentrantLock):可以多次获得同一把锁,但同时也需要同样多次释放锁;
  重入锁可以有中断响应、锁等待时限、设置公平锁;
  公平锁:即线程按先来后到的顺序获取资源;
  使用Condition,类似wait、notify;
3、读写锁(ReadWriteLock):线程间允许同时读(非阻塞),但多线程间(读、写),(写、写)操作是阻塞的;
4、信号量:允许指定多条线程进入临界区;
5、计数器(CountDownLatch):即指定多条线程完成某样工作,当前线程才继续执行(执行完一条线程,计数器就-1,不可复用);
6、循环栅栏(CyclicBarrier):即指定多条线程完成某样工作,这些线程就会暂停,等待再次唤醒执行(可复用);
  计数器与循环栅栏对比:
    0、可复用和不可复用;
    1、计数器 指定的线程运行到了计算器处,计数器就-1,该线程还是会执行后序操作;
    2、循环栅栏 等待所有指定线程运行到循环栅栏处,这些线程就会挂起;

线程池:
1、固定线程池内线程数;newFixedThreadPool
2、单一线程的线程池;newSingleThreadExecutor
3、不确定条数线程的线程池;newCacheThreadPool
4、自定义核心线程数和最大线程数的线程池;ThreadPoolExecutor
5、定时任务,可以指定每条线程执行任务的间隔(scheduleAtFixeRate、scheduleWithFixedDelay);
  scheduleAtFixeRate间隔为指定间隔;
  scheduleWithFixedDelay间隔为指定间隔+任务执行时间;

6、以上其中1、2、3的底层都是由4实现的
ThreadPoolExecutor构造函数有以下参数:
  corePoolSize:表示核心线程数(一直存活的);
  maximumPoolSize:表示线程池里最大线程数(当核心线程数不够用时);
  keepAliveTime:表示除了核心线程之外的其它线程,可以存活多久;
  unit:keepAliveTime的时间单位;
  workQueue:任务队列,在等待执行的任务;
  threadFactory:线程工厂,用来创建线程;
  handler:拒绝策略(线程池已经达到最大数量、任务队列也满了时,所做的操作);

7、线程增强:
线程池可以为每条线程编写线程执行前置方法(beforeExecure)、结束方法(afterExecute)、线程池结束方法(terminated);

8、使用线程池,开启线程的方法:
线程池实例.submit 、 线程池实例.execute()
  二者不同:
    submit有返回值,会把返回结果封装到Future<?>中,其中异常信息也会包含在Future<?>中;
    execute无返回值,有异常会直接抛出;

9、Fork/Join
可以把一个大任务,用线程分成若干个小任务(Fork),最后再把结果合并(Join);

Java虚拟机中的锁优化:
1、偏向锁:线程ID记录在对象头中(Mark Word),每次只需检查ID相符就可以直接进入代码块,若ID不同则说明有竞争,偏向锁 失效;
2、轻量锁:在栈帧中起一个锁记录,记录对象头;
  每次线程获取锁需要去更新对象头中指向栈帧中的记录,若成功则进入同步代码块;
  若失败,则判断对象头部是否已经指向了当前线程所在的栈当中,是则继续执行;
  若否则说明有多条线程竞争,膨胀为重量锁;

  偏向锁只适用于在只有一个线程执行同步代码块的情况;
  轻量级锁的“轻”在于当没有多线程竞争的情况下,只利用简单的CAS操作来代替操作系统互斥量在减少开销,所以要轻;

3、自旋锁:挂起再唤醒需要更多的消耗,让当前线程做几个空循环,可能过一会它就获得了锁;
4、锁消除:去除不能存在共享资源竞争的锁;

线程局部变量(ThreadLocal):
1、适用于线程间不用共享的,但每个线程都需要用到的资源;若使用一个普通全局变量,容易在多线程下被写乱;
2、ThreadLocal内部类似一个Map,键为线程本身,值为对应的资源,所以不同线程访问到是不同的资源;

无锁:
1、使用CAS(比较替换)达到无锁;
2、即需要三个参数,‘这个变量现在应该是怎么样的(预期值)’、‘这个值(当前值)’、‘需要赋予的新值(新值)’;
3、即比较预期值和当前值,若相等,则把当前值更新为新值;不相等,则说明被其它线程修改过了,得重新获取;
4、使用JDK并发包中的atomic包来进行CAS操作;

等待队列SynchronousQueue:
1、该队列容量为0,在线程中使用该队列,放入一个资源,该线程就会阻塞,直到该资源被另一线程取走;
2、容量为0不是指不能放数据或只能放一个数据,而是指配对通信机制;

单例模式:
1、单线程下的:私有构造函数,私有对象字段,静态的get,判断对象有无实例化,有则直接返回,无则实例后返回;
2、多线程1:私有构造函数,静态的对象并实例化,静态的get,(因为在JVM中,静态变量会在类加载时实例);
3、多线程2:私有构造函数,双重判断(先判断是否实例,无则加锁,在判断一次是否实例);
4、多线程3:私有构造函数,2会过早实例化,3太麻烦效率不高;使用一个内部类,需要返回的对象写内部类里,并静态修饰;

生产者-消费者模式:
1、即部分线程负责提交资源和数据,部分线程负责处理;
2、两部分线程可能并不同步(一个快一些,一个慢一些),所以需要一个中间的缓冲区来存储数据,以供生产者存入数据,消费者 取数据;
3、使用阻塞队列BlockigQueue作为中间缓冲区;
4、使用无锁的缓存框架Disruptor;

Future模式:
1、当数据提交给线程之后,线程会直接返回一个虚拟数据;
2、如果去获取这个虚拟数据的话,线程就会阻塞,直到真实数据准备好;
3、这样做的好处是,提交了数据之后,当前线程可以先执行其它任务,不必一直等待当前任务;
4、整个过程就像网购下单付款后,立刻收到的只是一个订单,快递得过几天才到,但这期间我们可以干其它事;
5、JDK中的Future模式(Callable<>接口,Future<>获取结果)

并行流水线:
1、适用于各条线程之间有很强的联系关系,该例子是要计算(B+C)*B/2,但数据在不同线程;
2、将算式分解为:thread1:A=B+C thread2:D=A*B thread3:D=D/2
3、流程:B、C数据进入线程1处理,线程1把A数据传递给线程2处理,线程2把D数据传递给线程3处理;
4、在此期间,当A数据到达线程2时,线程1又可以处理一个新的数据......

posted @ 2018-03-01 16:22  Drajun  阅读(223)  评论(0编辑  收藏  举报