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

    众所周知,在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进行操作。

转载于:https://www.cnblogs.com/zhaosq/p/10178265.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/449897.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4、容器虚拟化网络概述

Docker 网络 Docker 的网络实现其实就是利用了 Linux 上的网络名称空间和虚拟网络设备&#xff08;特别是 veth pair&#xff09;。 Linux 网络命名空间&#xff1a;https://www.jianshu.com/p/369e50201bce Linux虚拟网络设备之veth&#xff1a; https://segmentfault.com/a/1…

Linux whoami命令、Linux su命令、Linux w命令

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Linux whoami命令用于显示自身用户名称。 显示自身的用户名称&#xff0c;本指令相当于执行"id -un"指令。 语法 whoami […

Weekly 10

Algorithm 1.Remove Element What 移除数组中的指定元素,返回处理后的长度sum,并且数组前sum长度的元素为处理后的元素,不用额外数组&#xff0c;O(1)。How 用快慢指针,快指针遍历,遇到不等于指定元素的替换掉慢指针,然后慢指针前进一位即可。Key Codesclass Solution {public …

大数据计算:如何仅用1.5KB内存为十亿对象计数

摘要&#xff1a;AddThis的数据分析副总监Matt Abrams在High Scalability上发表了一篇文章&#xff0c;介绍了他们公司如何应对大数据。Matt Abrams表示&#xff0c;AddThis仅仅用了1.5KB内存的内存就计算了十亿个不同的对象&#xff0c;这与他们所使用的计算方法分不开的。 A…

C#关键字的个人理解与注释

C#关键字注释&#xff1a;abstract&#xff1a;抽象as&#xff1a;类型转换&#xff08;返回转换结果&#xff09;base&#xff1a;基类bool&#xff1a;布尔类型break&#xff1a;条件中断语句byte&#xff1a;字节case&#xff1a;条件语句catch&#xff1a;异常捕获后执行ch…

Linux declare命令、Linux tail 命令

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Linux declare命令用于声明 shell 变量。 declare为shell指令&#xff0c;在第一种语法中可用来声明变量并设置变量的属性([rix]即为变…

详解Nagios配置文件的逻辑关系

1.主配置文件/usr/local/nagios/etc/nagios.cfg a.定义了用户和组 b.定义了某些具体参数 c.定义了配置文件和可以存放配置文件的文件夹 d.通过开头的#号去注释选项以达到关闭配置的效果 e.更改配置后&#xff0c;可以通过命令 /usr/local/nagios/bin/nagios –v /usr/local/na…

10 步让你成为更优秀的程序员

这篇文章要介绍的&#xff0c;是我作为专业程序员这些年来学到的能真正提高我的代码质量和整体工作效率的10件事情。 1. 永远不要复制代码 不惜任何代价避免重复的代码。如果一个常用的代码片段出现在了程序中的几个不同地方&#xff0c;重构它&#xff0c;把它放到一个自己的函…

《流浪地球》 电影全集

《流浪地球》 电影全集 《流浪地球》是由郭帆导演&#xff0c;吴京特别出演&#xff0c;屈楚萧、李光洁、吴孟达等人主演的科幻片《流浪地球》宣布定档2019大年初一。同时&#xff0c;影片发布了一款定档预告片&#xff0c;预告片开头传来一段广播声音&#xff1a;“太阳急速老…

kotlin之plus、copyOf、reverse、forEach、filter、map、reduce、fold等函数解释和使用

kotlin之::函数调用、plus&#xff08;增加元素&#xff09;、copyOf&#xff08;复制数组&#xff09;、reverse&#xff08;翻转数组&#xff09;、forEach&#xff08;遍历数组&#xff09;、filter&#xff08;过滤数组&#xff09;、map函数操作及扩展、reduce函数、fold函…

linux 常用命令 杂记

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1.cat cat 命令用于连接文件并打印到标准输出设备上。 使用权限 所有使用者 2.Linux chgrp命令用于变更文件或目录的所属群组。 3.Linux…

C程序员要学C++吗?

最近网友问到这一问题&#xff0c;但我更希望被问的是“C程序员需要学面向对象编程吗&#xff1f;”&#xff0c;那就让我先从回答这一问题开始&#xff0c;并做适当的扩展。 就我的成长经历来看&#xff0c;C程序员必须学习面向对象编程&#xff01;面向对象编程语言有其天然的…

追女生心理研究(本人母胎单身,就是想做准备,并无其他意思)

聊天话题&#xff1a; 1。兴趣爱好&#xff1a;美食&#xff0c;旅游&#xff0c;宠物等 2。现在和曾经的自己&#xff0c;分享自己的经历 3。我变成我们&#xff0c;未来规划 4。分析隐私&#xff0c;比如一些小秘密 5。价值观&#xff0c;对未来的规划等 聊天话题技巧 …

dlopen 和 dlsym 动态调用函数

Linux/unix 提供了使用 dlopen 和 dlsym 方法动态加载库和调用函数&#xff0c;这套方法在 macOS 和 iOS 上也支持。dlopen 打开一个库&#xff0c;获取句柄。dlsym 在打开的库中查找符号的值。dlclose 关闭句柄。dlerror 返回一个描述最后一次调用dlopen、dlsym&#xff0c;或…

通过腾讯地图服务获取行政区划信息

接口说明地址&#xff1a; https://lbs.qq.com/webservice_v1/guide-region.html 以下是源代码及表创建脚本。 源码及相关文件下载转载于:https://www.cnblogs.com/challengesoflife/p/10405366.html

情感学习聊天方法

1.非正常聊天法 出人意料的聊天技巧&#xff0c;展示幽默感&#xff0c;让对方对自己产生兴趣 比如对方说&#xff1a;你的朋友圈好多美女啊。回答还好了&#xff0c;没有了。场面会一度尴尬 但可以这么说&#xff1a;你这样是在间接夸自己是美女。或者&#xff1a;还好啦&a…

面向对象设计的优点

一旦明白了软件设计的真谛&#xff08;参见《软件设计的真谛》&#xff09;&#xff0c;我们就更能理解面向对象设计的优点。简单说来&#xff0c;它更便于我们在软件中构建更真实的虚拟世界。 首先&#xff0c;对象的引入方便了在软件虚拟世界中模拟现实世界。现实世界是由很…

利用SVD-推荐未尝过的菜肴2

推荐未尝过的菜肴-基于SVD的评分估计 实际上数据集要比我们上一篇展示的myMat要稀疏的多。 from numpy import linalg as la from numpy import * def loadExData2():return[[0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 5],[0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 3],[0, 0, 0, 0, 4, 0, 0, 1, 0,…

在图像中截取小图并保存

实现以横向步长step_row、纵向步长step_col&#xff0c;在一幅大图上剪裁宽度为width、高度为height的小图像&#xff0c;图像命名形式为“数字(递增)_大图名”格式&#xff0c;将小图保存在argv[6]的文件夹中。 #include <opencv2/opencv.hpp> #include <string> …

Linux 文件与目录管理、ls、cd、pwd、mkdir、rmdir、cp、 rm

见&#xff1a;http://www.runoob.com/linux/linux-file-content-manage.html我们知道Linux的目录结构为树状结构&#xff0c;最顶级的目录为根目录 /。 其他目录通过挂载可以将它们添加到树中&#xff0c;通过解除挂载可以移除它们。 在开始本教程前我们需要先知道什么是绝对路…