小白白话技术之高并发多线程概述

        正如我上一批博文《小白白话技术之高并发连接数概述》中描述的那样,为了实现高并发,采取了最大的方式突破连接数的瓶颈,然而,解决连接数你仍然面临不小的挑战,那就是如果利用好多线程来进一步优化,这里就技术架构中应用多线程进行一个概要的表述。

       毫无疑问,多线程是个复杂的技术,但无疑多线程是一把利器,我们尝试循序渐进,,庖丁解牛的方式,逐层揭开多线程的神秘面纱,对其进行一个概要介绍。

       最基础的无疑是操作系统,进程,线程的概念,这块就不细说了,可以自行百度。那么我们还是要围绕主题展开,所以假设一些基本的概念还是有得。

        进程:在操作系统中能够独立运行,并且作为资源分配的基本单位。它表示运行中的程序。

        线程:是进程中的一个实例,作为系统调度和分派的基本单位。是进程中的一段序列,能够完成进程中的一个功能。

        简而言之就是进程是独立的,而线程是属于进程的,进程可以创建出许多线程,当然一个进程支持的线程数也是有限的,过多的线程会导致性能下降。操作系统给一个系统进程提供的空间是2GB ,而一个线程堆栈的空间默认在启动的时候是1MB,理论上最大线程数=2GB/1MB=2048。但是内存当然不可能完全拿来作线程的栈,所以实际数目要比这个值要小。你也可以通过连接时修改默认栈大小,将其改的比较小,这样就可以多开一些线程。如将默认栈的大小改成512K,这样理论上最多就可以开4096个线程。如果是同一台机器内的话,能起多少线程也是受内存限制的。

      好吧,我们知道线程的概念,那么线程具体有哪些内容呢?

      第一线程的状态,new 新建,runnable 就绪,dead 死亡,blocked 阻塞,作用呢就是控制线程的协同调度。

      第二线程的协同,多个线程彼此独立运行,但是也有需要协同的时候,比如访问共享资源产生资源竞争的时候,比如协作完成同一件事务时,等等。如何协同呢,sleep(),wait(),notify(),notifyall()以及若干和锁有关系的关键字。

      第三线程的内存模型JMM,具体说就是主内存和工作内存之间的关系。

      第四就是线程也是有名字的,你可以设置一个可辨识的名字。

      如何创建一个线程呢?

      第一种方式,设计一个类继承 Thread,实现Thread 的run()方法,然后这个新设计的类就可以创建出一个线程并处理run()方法里的逻辑了。

class YourThreadClass extends Thread{

    @Override

    public void run() {

        //业务逻辑

}

}

YourThreadClass thread1 = new YourThreadClass ();

通过thread1.start() 来启动这个线程。

      第二种方式,实现一个实现Runnable接口,并重写run()方法,这种方式是将业务逻辑单独实现到一个自定义类中,然后将这个自定义类传入给线程Thread类来创建线程。

class YourRunnableClass implements Runnable {

    @Override

    public void run() {

           //业务逻辑

    }

}

Thread thread2 = new Thread(new YourRunnableClass ());

通过thread1.start() 来启动这个线程。

这俩种创建方式是基本的线程创建方式,如果是简单用一下应该够用了,但是高并发下,这样创建管理线程就太简单了。

       第三种方式,线程池就实用多了,

newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

Java通过Executors来实现这些线程池,上面这四种方式适用于不同场景,如果不够用,你可以自己利用ThreadPoolExecutor实现一个线程池,为什么要用线程池,就是因为要考虑的因素太多了,而线程池解决了很多问题。

       第四种方式,就是异步线程,

如果说线程池是线程高效使用的第一种方式,那么异步线程就是第二种方式,具体怎么做呢?利用 Future,FutureTask来实现,通过Future以传递到线程对象Thread中新建一个线程执行。然后主线程就可以做别的事情了,那么这个方式和new Thread有什么区别,主要是可以子线程的计算结果方便的返回给主线程和灵活的控制方式。

通过Future<Integer> future = executor.submit(new Callable());异步提交任务,通过future.get()获取结果。

这里要说下Callable,这是实现业务逻辑的地方,类似于Runnable,区别是Callable可以返回数据到主线程。

public class YourCallable implements Callable<Integer> { 

    @Override 

    public Integer call() throws Exception { 

//业务逻辑

        return 计算结果; 

    } 

}

这样你的业务逻辑就可以提交到executor执行了。

线程是如何使用的呢?

第一种用法,创建一个线程,然后让这个线程去执行一个独立的任务,比如日志埋点。主线程不太关心子线程的情况。

第二种用法,创建一个线程,然后让子线程去执行一段计算逻辑,最后将结果返回给主线程,这种方式就要用到Future了,称之为future模式。

第三种用法,调度线程和工作线程结合使用,调度线程负责接收任务,并分配任务给工作线程来执行,称之为 master-worker模式。

第四种用法,这种用法指在线程之间加入一个缓存队列,有负责将任务加入队列的线程,有从队列里获取任务处理的线程。这样可以降低任务处理线程的压力,保证系统的稳定。

第五种用法,生产消费者模式,是指生产者和消费者俩类线程,通过缓存来协同,这样一个可以实现解构,另外可以降低消费线程的压力。

第六种用法, 不变模式,指将一个对象实现为不可变的,这样任何线程得到的对象都是一致的。

      多线程有一个非常重要的概念,就是锁,可以用synchronized关键字加锁,如果把关键字加到普通方法上那么就是在这个对象上加锁,如果关键字加到静态方法上,则是在这个类的class上加锁,如果加到代码段上则是在括号里的对象上加锁。只有持有锁的线程才可以进入同步的方法,这种方法可控性较差。另外一种加锁的方式是显式加锁,Lock,ReentrantlLock通过lock()加锁,通过unlock()释放锁。 锁会带来性能损耗,所以就有了锁粗化,锁消除,自旋锁,锁偏向等优化方式,当然不用锁最好,如无锁并发。   Lock有多个实现,ReentrantlLock是重入锁,意味着获得锁后,可以再次进入,可以再次获得锁,这对递归很有用;另外一个实现是ReentrantlReadWriteLock锁,这个锁是读写锁,意味着读是共享的,多个线程可以调用的,写是排他的,只有一个线程可以操作。

     Lock可以通过Condition实现类似synchronized的wait/notify的效果,实现线程间的协同。

     线程之间的协同,如synchronized的wait/notify/join、Lock的Condition、还有就是信号量(Semaphore),信号量有点类似于计数器,当有限的资源被同时允许的线程操作有数量限制时,就可以使用信号量,当达到信号量的上限是,其他线程就只能等待了,利用这种特性,可以控制线程的稳定性,同时也可以做排它锁或共享锁。另外一种协同机制就是CountDownLatch,CountDownLatch 也类似一个计数器,不同的时,这个计数器记录的是完成任务的线程数量,当所有线程完成之前,主线程是阻塞的,完成后主线程开始继续执行。另外有类似功能的是CyclicBarrier,它比CountDownLatch要特性更丰富一些。Exchanger是一个线程之间协作的工具类,用于线程之间交换数据,俩个线程在同步点发生数据交换后,继续执行,这个同步点就是指调用 exchange()方法的位置。

上述是多线程比较简单的协同,负载的协同往往要和特定的数据结构结合,比如阻塞队列,比如ForkJoin框架。并发队列主要有俩种,一种高性能队列concurrentLinkedQueue,和BlockingQueue,还有一种Deque队列即双端队列,这种队列增加操作功能,但性能不如BlockingQueue。

         最后在讨论下CompletableFuture ,用来完成对多线程的编排,满足更复杂的多线程场景,CompletableFuture 提供了很多函数,最终要的特性应该是回调函数。

比如异步合并子线程处理的结果而不阻塞主线程。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值