当前位置:首页 > 后端开发 > Java并发编程(多线程)中的相关概念

Java并发编程(多线程)中的相关概念

6个月前 (05-25)16

    众所周知,在Java的知识体系中,并发编程是非常重要的一环,也是面试中必问的题,一个好的Java程序员是必须对并发编程这块有所了解的。

并发必须知道的概念

在深入学习并发编程之前,我们需要了解几个基本的概念。

同步和异步

同步和异步用请求返回调用的方式来理解相对简单。

同步:可以理解为发出一个请求后,必须等待返回结果才能执行后续的操作。

异步:请求发出后,不需要等待返回结果,可以继续执行后续操作,异步请求更像是在另一个 “空间” 中处理请求的结果,这个过程不会影响请求方的其他操作。

举个生活中的例子,比如我们去实体店买衣服,挑选完款式后下单让售货员去仓库拿货,在售货员拿货的过程你需要在店里等待,直到售货员把衣服交给你后才算购物成功,这就相当于同步的过程。

不过,如果是在网上购物的话,我们只需下单并完成支付,对我们来说整个购物过程就算完成了。网上的商家接到订单会帮我们加紧安排送货,这段时间我们可以去做其他的事,比如去外面打个篮球之类的。等送货上门并签收商品就完事了,这个过程就相当于异步。

并发和并行

并发和并行的功能很相似,两者都可以表示多个任务一起执行的情况,但本质上两者其实是有区别的。

严格意义上来说,并行的多任务是真实的同时执行而并发更多的情况是任务之间交替执行,系统不停的在多个任务间切换执行,也就是 “串行” 执行

最直接的例子的就是我们的计算机系统,在单核CPU时代,系统表面上能同时进行多任务处理,比如听歌的同时又浏览网页,但真实环境中这些任务不可能是真实并行的,因为一个CPU一次只能执行一条指令,这种情况就是并发,系统看似能处理多任务是因为不停的切换任务,但因为时间非常短,所以在我们的感官来说就是同时进行的。而计算机系统真实的并行是随着多核CPU的出现才有的。

临界区

临界区表示公共资源或是共享数据,可以被多个线程使用。但是每次只能有一个线程使用它,一旦临界区的资源被占用,其他线程就必须等到资源释放后才能继续使用该资源。在Java程序开发中,对于这样的资源一般都需要做同步的操作,例如下面的这段代码,用的就是synchronized关键字来对临界区资源进行同步

public class SyncTest implements Runnable {
//临界区资源 public static SyncTest instance = new SyncTest(); @Override public void run() { synchronized (instance) { } } public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new SyncTest()); Thread t2 = new Thread(new SyncTest()); t1.start(); t2.start(); t1.join(); t2.join(); } }

阻塞和非阻塞

阻塞和非阻塞通常用来形容多线程间的相互影响。比如一个线程占用了临界区的资源,那么其他需要这个资源的线程就必须等待。等待的过程会使线程挂起,也就是阻塞。如果临界区的资源一直不释放的话,那么其他阻塞的线程就都不能工作了。

非阻塞则相反,强调的是线程之间并不互相妨碍,所有的线程都会不断尝试向前执行。

死锁、饥饿和活锁

这三种情况表示的是多线程间的活跃状态,对于线程来说,以上的情况都是 “非友好” 的状态。

1、死锁一般是指两个或者两个以上的线程互相持有对方所需的资源,并且永远在等待对方释放的一种阻塞状态。例如有两个线程A和B同时共享临界区的资源C,当A占用C时,B处于阻塞状态,然而A的释放需要用到B的资源,这样一来,就变成了A一直在等待B,B也一直在等待A,互相之间永远在等待对方释放的状态。

一般来说,死锁的发生是由于程序的设计不合理导致,而且死锁很难解决,最好的方式就是预防

2、饥饿是指某一个或者多个线程因为种种原因无法获得所需的资源,导致一直无法执行。比如它的线程优先级太低,而高优先级的线程不断抢占它所需的资源,导致低优先级资源无法工作。

3、活锁的情况是线程一种非常有趣的情况,在生活中我们可能会碰到这样的情况,那就是出门的时候可能会遇到有人要进门,你打算让他先进门,他又打算让你先出门,结果,两个人都互相退后了,然后你打算先出门时对方也向前一步,来来回回就一直卡在门口。当然,这种事情正常人很快就能解决,但如果是线程碰到就没那么幸运了。

如果两个线程占用着公共的资源,并且秉承着 “谦让” 的原则,主动把资源让给他人使用,你让我也让,这样就造成资源在两个线程间不断跳动但线程之间都拿不到资源的情况,这样的情况就是活锁了

线程安全

线程安全指的是多线程的安全。如果一段程序可以保证被多线程访问后仍能保持正确性,那么程序就是线程安全的。一般来说,线程安全注重的是多线程开发中的共享数据的安全。就比如下面这段代码:

public class ThreadSafety implements Runnable{
//共享数据 public static int i = 0; public void increase(){ for (int j= 0;j<10; j++){ i++; } }
@Override public void run() { increase(); } public static void main(String[] args) throws Exception{ ThreadSafety demo = new ThreadSafety(); Thread t1 = new Thread(demo); Thread t2 = new Thread(demo); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }

两个线程 t1 和 t2 同时开启,执行run方法,在我们的预想中,如果是线程安全的话,那么main的执行结果应该是20,但是因为 i 是共享数据,而程序没有对 i 的操作做同步的处理,最终运行的结果并不是20,所以这种情况就不是线程安全的情况。

解决的办法也比较简单,可以利用synchronized关键字来修饰方法或代码块,这部分的知识也是并发编程中非常重要的一块。

改进后的代码如下:

public class ThreadSafety implements Runnable{
//共享数据 public static int i = 0; public void increase(){
synchronized(this){
 for(int j= 0;j<10; j++){ i++; }
}
 }
@Override public void run() { increase(); } public static void main(String[] args) throws Exception{ ThreadSafety demo = new ThreadSafety(); Thread t1 = new Thread(demo); Thread t2 = new Thread(demo); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(i); } }

 此时,两个线程 t1 和 t2 同时开启,执行run方法,资源i就是独立的了,两个线程会切换执行,当t1执行的时候,会通过synchronized同步锁将i锁住,等到t1执行完毕释放锁了之后,t2才会执行对i进行操作。

作者:zsq_fengchen
来源链接:https://www.cnblogs.com/zhaosq/p/10178265.html

“Java并发编程(多线程)中的相关概念” 的相关文章

Java 多线程之线程状态图

Java 多线程之线程状态图

一.线程基本状态图             图中是线程运行的基本状态:线程调用start()方法开始...

Java多线程看这一篇就足够了(吐血超详细总结)

Java多线程看这一篇就足够了(吐血超详细总结)

进程与线程 进程是程序的一次动态执行过程,它需要经历从代码加载,代码执行到执行完毕的一个完整的过程,这个过程也是进程本身从产生,发展到最终消亡的过程。多进程操作系统能同...

Java中空对象(null)引用方法及属性简单分析!

Java中空对象(null)引用方法及属性简单分析!

在Java中,对象往往包含属性、方法及一个存储空间,若一个对象的属性和方法是空的则可认为这是一个空对象。 一个空对象也是对象,同样通过对象名引用方法或属性,但和一般对象...

Java判断对象是否为Null/空

package com.taiping.test; import java.lang.reflect.Field; import java.lang.reflect.Type...

【java 多线程】多线程并发同步问题及解决方法

【java 多线程】多线程并发同步问题及解决方法

一、线程并发同步概念 线程同步其核心就在于一个“同”。所谓“同”就是协同、协助、配合,“同步”就是协同步调昨,也就是按照预定的先后顺序进行运行,即“你先,我等, 你做完,我再做”。...

Java集合,集合的方法,集合的遍历

Java集合,集合的方法,集合的遍历

package com.atgui.java; import org.junit.Test; import java.u...

java--poi读取excel图片和内容(支持03版本)

有的时候需要将excel中所包含的图片在导入的时候取出来存到服务器中, 详细实现代码如下: package com.liuf.util; import java....

Elasticsearch 2.X 版本Java插件开发简述

Elasticsearch 2.X 版本Java插件开发简述

1:elasticsearch插件分类简述 2:Java插件开发要点 3:如何针对不同版本elasticsearch提供多版本的插件 4:插件具有外部依赖时遇到的一些问...

idea JavaFx项目搭建报错 类文件具有错误的版本55.0,应为52.0

idea JavaFx项目搭建报错 类文件具有错误的版本55.0,应为52.0

JavaFx项目编译提示:..类文件具有错误的版本55.0,应为52.0.. 项目场景: 问题描述:...

CKEditor3.6.2与CKFinder2.1整合(java版本)

CKEditor3.6.2与CKFinder2.1整合(java版本)

先介绍下ckeditor的单独配置,在介绍下eidtor与finder的整合 一、CKEditor的使用 1.下载地址 http://ckeditor.com/downloa...