并发编程(一)—— 并发设计原理

并发编程(一)—— 并发设计原理

一. 基本的并发概念

1.1进程与线程

进程是操作系统进行资源分配的最小单位,其中资源包括:cpu、内存空间、磁盘IO等。同一进程中的多个线程共享该进程中的全部系统资源,而进程和进程之间是相互独立的。

举个例子,你的电脑同时在运行QQ和微信,这时候QQ和微信是两个进程他们的资源相互独立,QQ运行时又会开启多条线程进行工作,这些线程可以共享QQ进程的资源。

线程是CPU调度的最小单位,必须依赖于进程而存在。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。

1.2CPU核心数和线程数的关系

多核心:也指单芯片多处理器( Chip Multiprocessors,简称CMP),CMP是由美国斯坦福大学提出的,其思想是将大规模并行处理器中的SMP(对称多处理器)集成到同一芯片内,各个处理器并行执行不同的进程。这种依靠多个CPU同时并行地运行程序是实现超高速计算的一个重要方向,称为并行处理。

多线程: Simultaneous Multithreading.简称SMT.让同一个处理器上的多个线程同步执行并共享处理器的执行资源。

核心数、线程数:目前主流CPU都是多核的。增加核心数目就是为了增加线程数,因为操作系统是通过线程来执行任务的,一般情况下它们是1:1对应关系,也就是说四核CPU一般拥有四个线程。但 Intel引入超线程技术后,使核心数与线程数形成1:2的关系。

1.3 并发与并行

并发:指一定时间段内,应用通过交替执行不同的任务:比如单CPU核心下执行多线程并非是同时执行多个任务,如果你开两个线程执行,就是在你几乎不可能察觉到的速度不断去切换这两个任务,已达到"同时执行效果",其实并不是的,只是计算机的速度太快,我们无法察觉到而已。

并行:指应用能够同时执行不同的任务,例:吃饭的时候可以边吃饭边打电话,这两件事情可以同时执行。

1.4 同步

控制同步:例如,当一个任务的开始依赖于另一个任务的结束时,第二个任务不能在第一个任务完成之前开始。就好比流水线上,后一步操作要建立在前一步操作完成的基础上进行。

数据访问同步:当两个或更多任务访问共享变量时,在任意时间里,只有一个任务可以访问该变量。就好比一个盒子里面有很多糖,可盒子的开口很小一次只能通过一个小朋友的手,这时候有好多小朋友来拿糖,因为开口大小的限制,每次只能一个小朋友从盒子里面抓糖。

1.5 不可变对象

不可变对象是一种非常特殊的对象。在其初始化后,不能修改其可视状态(其属性值)。如果想修改一个不可变对象,那么你就必须创建一个新的对象。就比如java中的String类。当你给一个String对象赋值时,会创建一个新的String对象。

不可变对象的主要优点在于它是线程安全的。你可以在并发应用程序中使用它而不会出现任何问题。

二.并发应用程序可能出现的问题

2.1 线程之间的安全性

因为同一个进程中的线程可以共享进程的资源,如果有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。

2.2 死锁

为了解决线程之间的安全性引入了Java的锁机制,而一不小心就会产生Java线程死锁的多线程问题。

当两个(或多个)任务正在等待必须由另一线程释放的某个共享资源,而该线程又在等待必须由前述任务之一释放的另一共享资源时,并发应用程序就出现了死锁。

就好比两个人A持有锤子,B持有铲子,A的工作这时候要用到铲子和锤子,他就找B要铲子,而正好这时候B的工作也要用到铲子和锤子,B就找A要锤子。A说你先把铲子给我用,我用好了再给你。B不肯,凭什么你先用,为什么你不先把锤子给我用,我用完了再给你。于是两个都不示弱都不肯把自己持有的工具借给对方,这样两个人的工作就无法继续下去,矛盾尖锐化后就会打起来了。

有上面的例子我们可以看到当系统同时出现如下四种条件时,就会导致死锁的情况。其称为Coffman条件。

  1. 互斥:死锁中涉及的资源必须是不可共享的。一次只有一个任务可以使用该资源。就好比锤子和铲子同一时间只能用于完成一个任务。
  2. 占有并等待条件:一个任务在占有某一互斥的资源时又请求另一互斥的资源。当它在等待时,不会释放任何资源。就比如上面的例子,A和B都不肯先把自己的工具给对方使用,同时又想获取对方的工具。
  3. 不可剥夺:资源只能被那些持有它们的任务释放。就比如工具总不能去抢吧,大家都是文明人。
  4. 循环等待:任务1正等待任务2所占有的资源,而任务2又正在等待任务3所占有的资源,以此类推,任务n又正在等待任务1所占有的资源,这样就出现了循环等待。

2.3 线程太多了会将服务器资源耗尽形成死机当机

线程数太多有可能造成系统创建大量线程而导致消耗完系统内存以及CPU的“过渡切换”,造成系统的死机,那么我们该如何解决这类问题呢?

某些系统资源是有限的,如文件描述符。多线程程序可能耗尽资源,因为每个线程都可能希望有一个这样的资源。如果线程数相当大,或者某个资源的侯选线程数远远超过了可用的资源数则最好使用资源池。一个最好的示例是数据库连接池。只要线程需要使用一个数据库连接,它就从池中取出一个,使用以后再将它返回池中。资源池也称为资源库。

注意 本文参考书籍《精通java并发编程》和 腾讯课堂享学课堂笔记,只用于个人学习使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值