美文网首页
多线程基础

多线程基础

作者: 985cf3d148b0 | 来源:发表于2016-09-08 16:15 被阅读32次

    1.关键术语和多线程基础介绍

    关于多线程的基础知识请卡如下的文章:

    高并发Java(1):前言

    2.基础

    参考:高并发Java(2):多线程基础

    关键句子:Java当中线程的概念和操作系统级别线程的概念是类似的。事实上,Jvm将会把Java中的线程映射到操作系统的线程区

    线程状态图:

     

    当new出一个线程时,其实线程并没有工作。它只是生成了一个实体,当你调用这个实例的start方法时,线程才真正地被启动。启动后到Runnable状态,Runnable表示该线程的资源等等已经被准备好,已经可以执行了,但是并不表示一定在执行状态,由于时间片轮转,该线程也可能此时并没有在执行。对于我们来说,该线程可以认为已经被执行了,但是是否真实执行,还得看物理cpu的调度。当线程任务执行结束后,线程就到了Terminated状态。

    有时候在线程的执行当中,不可避免的会申请某些锁或某个对象的监视器,当无法获取时,这个线程会被阻塞住,会被挂起,到了Blocked状态。如果这个线程调用了wait方法,它就处于一个Waiting状态。进入Waiting状态的线程会等待其他线程给它notify,通知到之后由Waiting状态又切换到Runnable状态继续执行。当然等待状态有两种,一种是无限期等待,直到被notify。一直则是有限期等待,比如等待10秒还是没有被notify,则自动切换到Runnable状态。

    关键方法介绍:

    stop():会释放所有monitor,立即停止掉线程  (过于暴力,不推荐)

    intterrupt():线程中断 (并不是一定中断,它只是要求线程自己在合适的时机中断自己。)

    suspend():挂起,但不会挂起

    resume():继续执行,(如果加锁发生在resume()之前 ,则死锁发生)

    yeild():把自己占有的cpu时间释放掉,然后和其他线程一起竞争(注意yeild的线程还是有可能争夺到cpu,注意与sleep区别)

    join():等待其他线程结束,(让主线程等待t1,t2结束以后再结束。)

    Daemon():守护线程(如:在后台默默地完成一些系统性的服务)

    setPriority:线程优先级(并不一定是高优先级一定先完成。再多次运行后发现,高优先级完成的概率比较大,但是低优先级还是有可能先完成的。)

    synchronized有三种加锁方式:

    指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。

    直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。

    直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。

    3Java内存模型和线程安全

    Java内存模型见下图:

    详细看:线程安全

    4.无锁篇

    详细看:高并发Java(4):无锁

    5.JDK并发包

    synchronized有三种加锁方式

    指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。

    直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。

    直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。

    作用于实例方法,则不要new两个不同的实例

    作用于静态方法,只要类一样就可以了,因为加的锁是类.class,可以new两个不同实例。

    lock分别有:ReentrantLock、ReetrantReadWriteLock.ReadLock 和 ReetrantReadWriteLock.WriteLock,即重入锁、读锁和写锁

    5.1ReentrantLock

    相比于synchronized,ReentrantLock在功能上更加丰富,它具有可重入、可中断、可限时、公平锁等特点。

    5.1.1可重入

    lock.lock();

    lock.lock();

    ock.unlock();

    lock.unlock();

    5.1.2可中断(与synchronized不同的是,ReentrantLock对中断是有响应的)

    场景:当持有锁的线程长期不释放锁时,正在等待的线程可以选择放弃等待,改为处理其他事情

    lock.lockInterruptibly()能够响应中断

    5.1.3可限时

    ock.tryLock(long timeout, TimeUnit unit)来实现可限时锁,参数为时间和单位。

    5.1.4公平锁

    场景:多个线程在等待同一个锁时,必须按照申请锁的时间顺序排队等待

    这个锁能保证线程是先来的先得到锁

    5.1.5锁可以绑定多个条件

    场景:ReentrantLock 对象可以同时绑定多个 Condition 对象;需要多次调用 newCondition()方法即可。而且我们还可以通过绑定 Condition 对象来判断当前线程通知的是哪些线程(即与 Condition 对象绑定在一起的其他线程)。

    6.JDK并发包

    6.1线程池

    Executers分类:

    new FixedThreadPool 固定数量的线程池,线程池中的线程数量是固定的,不会改变。

    1.newFixedThreadPool 与 cacheThreadPool 差不多,也是能 reuse 就用,但不能随时建新的线程。

    2.其独特之处:任意时间点,最多只能有固定数目的活动线程存在,此时如果有新的线程要建立,只能放在另外

    的队列中等待,直到当前的线程中某个线程终止直接被移出池子。

    new SingleThreadExecutor 单一线程池,线程池中只有一个线程。

    1.单例线程,任意时间池中只能有一个线程

    new CachedThreadPool 缓存线程池,线程池中的线程数量不固定,会根据需求的大小进行改变。

    1.缓存型池子,先查看池中有没有以前建立的线程,如果有,就 reuse 如果没有,就建一个新的线程加入池中

    2.缓存型池子通常用于执行一些生存期很短的异步型任务 因此在一些面向连接的 daemon 型 SERVER 中用

    得不多。但对于生存期短的异步任务,它是 Executor 的首选。

    3.能 reuse 的线程,必须是 timeout IDLE 内的池中线程,缺省 timeout 是 60s,超过这个 IDLE 时长,线程

    实例将被终止及移出池。

    new ScheduledThreadPool 计划任务调度的线程池,用于执行计划任务,比如每隔5分钟怎么样,

    1.这个池子里的线程可以按 schedule 依次 delay 执行,或周期执行

    6.2callback和future

    Callable与Runnable的功能大致相似,Callable中有一个call()函数,但是call()函数有返回值

    Executor就是Runnable和Callable的调度容器,Future就是对于具体的Runnable或者Callable任务的执行结果进行

    取消、查询是否完成、获取结果、设置结果操作。get方法会阻塞,直到任务返回结果

    7.Volatile关键字

    使用建议:在两个或者更多的线程需要访问的成员变量上使用 volatile。当要访问的变量已在 synchronized 代码块中,或者为常量时,没必要使用 volatile。

    8.阻塞队列和阻塞栈

    8.1阻塞队列

    阻塞队列的接口是 java.util.concurrent.BlockingQueue,它有多个实现类:ArrayBlockingQueue、DelayQueue、LinkedBlockingQueue、PriorityBlockingQueue、SynchronousQueue 等  

    实现原理:实现了一个有界队列,当队列满时,便会阻塞等待,直到有元素出队,后续的元素才可以被加入队列。

    8.2阻塞栈

    阻塞栈与阻塞队列相似,只是它是 Java 6 中加入的新特性,阻塞栈的接口java.util.concurrent.BlockingDeque 也有很多实现类,使用方法也比较相似

    9障碍器

    使用时需要导入java.util.concurrent.CylicBarrier。它适用于这样一种情况:你希望创建一组任务,它们并发地执行工作,另外的一个任务在这一组任务并发执行结束前一直阻塞等待,直到该组任务全部执行结束,这个任务才得以执行。这非常像 CountDownLatch,只

    是 CountDownLatch 是只触发一次的事件,而 CyclicBarrier 可以多次重用。

    10并发新特性—信号量 Semaphore

    以控制某个资源被同时访问的任务数,它通过acquire()获取一个许可,release()释放一个许可。如果被同时访问的任务数已满,则其他 acquire 的任务进入等待状态,直到有一个任务被 release 掉,它才能得到许可。

    参考文档:java并发编程

    相关文章

      网友评论

          本文标题:多线程基础

          本文链接:https://www.haomeiwen.com/subject/oopsettx.html