Java并发总结(一)

部分图片源于三分恶 ,作者老三

并行和并发的区别

并发(concurrency):把任务在不同的时间点交给处理器进行处理。在同一时间点,任务并不会同时运行。
并行(parallelism):把每一个任务分配给每一个处理器独立完成。在同一时间点,任务一定是同时运行。
并发不是并行。并行是让不同的代码片段同时在不同的物理处理器上执行。并行的关键是同时做很多事情,而并发是指同时管理很多事情,这些事情可能只做了一半就被暂停去做别的事情了。
在很多情况下,并发的效果比并行好,因为操作系统和硬件的总资源一般很少,但能支持系统同时做很多事情。
借用github上的一幅图理解
Java并发总结(一)
并发就是多个队(多个任务)等待一个咖啡机(处理器/CPU),并行就是多个队有多个咖啡机

什么是多线程中的上下文切换

通过上图可以看到,多线程的时候,多个任务要处理,CPU资源是有限的,每个队看作一个任务,每个人看作一个时间片,当一个时间片到了当前的任务就要让出CPU,去处理别的任务。
Java并发总结(一)

多线程会共同使用一组计算机上的CPU,而线程数大于给程序分配的CPU数量时,为了让各个线程都有执行的机会,就需要轮转使用CPU。不同的线程切换使用CPU发生的切换数据等就是上下文切换。

守护线程和本地线程

java中的线程分为两种:守护线程(Daemon)和用户线程(User)。任何线程都可以设置为守护线程和用户线程,通过方法Thread.setDaemon(boolon);true则把该线程设置为守护线程,反之则为用户线程。Thread.setDaemon()必须在Thread.start()之前调用,否则运行时会抛出异常。两者的区别:唯一的区别是判断虚拟机(JVM)何时离开,Daemon是为其他线程提供服务,如果全部的UserThread已经撤离,Daemon没有可服务的线程,JVM撤离。也可以理解为守护线程是JVM自动创建的线程(但不一定),用户线程是程序创建的线程;比如JVM的垃圾回收线程是一个守护线程,当所有线程已经撤离,不再产生垃圾,守护线程自然就没事可干了,当垃圾回收线程是Java虚拟机上仅剩的线程时,Java虚拟机会自动离开。
扩展:ThreadDump打印出来的线程信息,含有daemon字样的线程即为守护进程,可能会有:服务守护进程、编译守护进程、windows下的监听Ctrl+break的守护进程、Finalizer守护进程、引用处理守护进程、GC守护进程。

线程的状态及线程间的通信

Java并发总结(一)
当线程间是可以共享资源时,线程间通信是协调它们的重要的手段。Object类中wait()\notify()\notifyAll()方法可以用于线程间通信关于资源的锁的状态。

ThreadLocal存储上下文信息

在控制层拦截请求把用户信息存入ThreadLocal,这样我们在任何一个地方,都可以取出ThreadLocal中存的用户数据。
Java并发总结(一)
使用

/**
 * 当前用户线程
 */
public class AuthThreadLocal {
 
    private AuthThreadLocal() {
    }
 
    private static final ThreadLocal<AuthTokenData> LOCAL = new ThreadLocal<>();
 
    /**
     * 将user放到threadLocal
     *
     * @param auth user
     */
    public static void setAuth(AuthTokenData auth) {
        LOCAL.set(auth);
    }
 
    /**
     * 返回当前线程中的user对象
     *
     * @return 返回当前线程中的user对象
     */
    public static AuthTokenData getAuth() {
        return LOCAL.get();
    }
 
    /**
     * 删除当前线程中的user对象
     */
    public static void remove() {
        LOCAL.remove();
    }
}

悲观锁和乐观锁

https://developer.aliyun.com/article/852353?spm=a2c6h.26396819.0.0.7a5f3e18mUYSxz

Java线程池

https://developer.aliyun.com/article/852287?spm=a2c6h.26396819.0.0.7a5f3e18MrrERE

volatile实现原理

https://developer.aliyun.com/article/848755?spm=a2c6h.26396819.0.0.7a5f3e18an2G1Y

Semaphore(信号量)

Java中的Semaphore是一种新的同步类,它是一个计数信号。从概念上讲,从概念上讲,信号量维护了一个许可集合。如有必要,在许可可用前会阻塞每一个acquire(),然后再获取该许可。每个release()添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore只对可用许可的号码进行计数,并采取相应的行动。信号量常常用于多线程的代码中,比如数据库连接池。

public class SemaphoreTest {
    private static final int THREAD_COUNT = 30;
    private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_COUNT);
    private static Semaphore s = new Semaphore(10);

    public static void main(String[] args) {
        for (int i = 0; i < THREAD_COUNT; i++) {
            threadPool.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        s.acquire();
                        System.out.println("save data");
                        s.release();
                    } catch (InterruptedException e) {
                    }
                }
            });
        }
        threadPool.shutdown();
    }
}
上一篇:python学习之路-2 初识python数据类型


下一篇:频频曝出程序员被抓,我们该如何避免面向*编程?