并发

作者: 机器不能学习 | 来源:发表于2018-09-05 21:51 被阅读0次

    总结一些并发的基础知识,方便以后学习。


    什么是并发,什么是并行?

    并发不是同时完成的,而是每一项任务花费一点时间,在多个任务中来回。

    并行是同时进行的,同一时间多个任务。

    cpu的多核占有,一般是由系统决定。


    线程的状态。

    状态分为,sleep() 放弃处理,进入休眠,让出位置给其他线程

    join() /interrupt()中断线程   wait() 处于等待池,直到被唤醒   notify() 唤醒线程

    调用方法,直接用Thread.方法()进行调用


    关键字

    synchronized

    可以锁定普通方法,静态方法,代码块

    synchronized锁住的是括号里的对象,而不是代码。对于非static的synchronized方法,锁的就是对象本身也就是this。

    synchronized(this)以及非static的synchronized方法,只能防止多个线程同时执行同一个对象的同步代码段。

    volatile

    因为每个线程都是直接到内存中读取该值,每个线程都互相可见,所以该值会保持准确。

    每个线程的共同变量可以用这个关键字修饰。

    补充:内存模型中的可见性,原子性,有序性

    可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。也就是一个线程修改的结果。另一个线程马上就能看到。比如:用volatile修饰的变量,就会具有可见性。volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存。所以对其他线程是可见的。但是这里需要注意一个问题,volatile只能让被他修饰内容具有可见性,但不能保证它具有原子性。比如 volatile int a = 0;之后有一个操作 a++;这个变量a具有可见性,但是a++ 依然是一个非原子操作,也就是这个操作同样存在线程安全问题。

      在 Java 中 volatile、synchronized 和 final 实现可见性。

    原子性:

    原子是世界上的最小单位,具有不可分割性。比如 a=0;(a非long和double类型) 这个操作是不可分割的,那么我们说这个操作时原子操作。再比如:a++; 这个操作实际是a = a + 1;是可分割的,所以他不是一个原子操作。非原子操作都会存在线程安全问题,需要我们使用同步技术(sychronized)来让它变成一个原子操作。一个操作是原子操作,那么我们称它具有原子性。java的concurrent包下提供了一些原子类,我们可以通过阅读API来了解这些原子类的用法。比如:AtomicInteger、AtomicLong、AtomicReference等。

      在 Java 中 synchronized 和在 lock、unlock 中操作保证原子性。

    有序性:

     Java语言提供了 volatile 和 synchronized 两个关键字来保证线程之间操作的有序性,volatile

    是因为其本身包含“禁止指令重排序”的语义,synchronized 是由“一个变量在同一个时刻只允许一条线程对其进行 lock操作”这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。


    线程类

    Thread 

    继承线程类,因为线程类本来就实现了runnable方法,可用start()启用线程

    如果想让线程类获取数据,那么就用同名函数传参。

    Runnable

    实现这个接口,重写run方法即可

    Callable

    使用ExecutorService、Callable、Future实现有返回结果的线程

    这也是唯一能返回结果的线程


    线程池

    ExecutorService

    可以实例多种线程池,没过多了解。简单科普

    newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。 如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

    newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

    newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程, 当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。

    newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

    newSingleThreadExecutor:创建一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求。

    callable用submit提交   runnable 用execute执行

    只需要放入线程即可,线程池的数量达到设定数量后,不会让放入,而是重复使用


    线程容器

    放几个我博客转发的连接

    map的线程安全https://blog.csdn.net/qq_40800349/article/details/79788165

    https://blog.csdn.net/qq_40800349/article/details/79788117

    还有Conllections.synchronizedList也是线程安全的容器


    ThreadLocal类

    独立变量,对于每一个线程,都会将该值副本,成为自己独有的变量。

    ThreadLocalMap 可以用这个类写一个map数据类型存入属于用户自己的数据

    lock类

    并发越高效率更高的锁。

    用法ReentrantLock lock=new ReentrantLock();得到锁

    lock.lock(); 锁上    lock.unlock() 释放锁 释放锁最好放在finall中

    相关文章

      网友评论

          本文标题:并发

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