博客
关于我
深入理解java并发编程基础篇(一)-------并发编程相关概念
阅读量:217 次
发布时间:2019-02-28

本文共 3341 字,大约阅读时间需要 11 分钟。

一、前言

拖了很久的并发编程,今天会开始第一篇,主要分为俩大部分进行学习:分为基础篇以及进阶篇,下面就开始基础篇的学习。

  
(想自学习编程的小伙伴请搜索,更多行业相关资讯更有行业相关免费视频教程。完全免费哦!)

二、并发编程的相关概念

2.1.同步(Sync)与异步(Async)

2.2.1 同步(Sync)

所谓同步,就是发出一个功能调用时,在没有得到结果之前,该调用就不返回或继续执行后续操作。

  
  根据这个定义,Java中所有方法都是同步调用,应为必须要等到结果后才会继续执行。 我们在说同步、异步的时候,一般而言是特指那些需要其他端协作或者需要一定时间完成的任务。简单来说,同步就是必须一件一件事做,等前一件做完了才能做下一件事。

2.2.2 异步(Async)

异步与同步相对,当一个异步过程调用发出后,调用者在没有得到结果之前,就可以继续执行后续操作。 当这个调用完成后,一般通过状态、通知和回调来通知调用者。对于异步调用,调用的返回并不受调用者控制。

如下图示:

在这里插入图片描述

2.2.并发(Concurrency)和并行(Parallelism)

并发和并行是两个非常容易被混淆的概念。他们都可以表示两个或者多个任务一起执行,但是侧重点有所不同。并发偏重于多个任务交替执行,而多个任务之间有可能还是串行的,而并行是真正意义上的“同时执行”,如下图:

在这里插入图片描述

  实际上,如果系统内只有一个CPU,而使用多进程或者多线程任务,那么真实环境中这些任务不可能是真实并行的,毕竟一个CPU一次只能执行一条指令,在这种情况下多进程或者多线程就是并发的,而不是并行的(操作系统会不停地切换多任务)。真实的并行也只可能出现在拥有多个CPU的系统中(比如多核CPU)。

2.3.临界区

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

package com.MyMineBug.demoRun.test;/** *  * @author 18360 * */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();    }}

2.4. 阻塞(Blocking)和非阻塞(Non-Blocking)

阻塞和非阻塞通常用来形容很多线程间的相互影响。比如一个线程占用了共享资源,那么其他所有需要这个资源的线程就必须在这个临界区中等待。等待会导致线程挂起,这种情况就是阻塞。此时,如果占用资源的线程一直不愿意释放资源,那么其他线程阻塞在这个临界区上的线程都不能工作。

非阻塞的意思与之相反,它强调没有一个线程可以妨碍其他线程执行,所有的线程都会尝试不断向前执行

2.5.死锁(Deadlock)、饥饿(Starvation)和活锁(Livelock)

2.5.1 死锁(Deadlock)

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

以下是死锁的简单例子:

package com.MyMineBug.demoRun.test;public class Demo1 {	public static String obj1 = "obj1";	public static String obj2 = "obj2";	public static void main(String[] args) {		Thread a = new Thread(new Lock1());		Thread b = new Thread(new Lock2());		a.start();		b.start();	}}	class Lock1 implements Runnable {			@Override		public void run() {			try {				System.out.println("Lock1 running");				while (true) {					synchronized (Demo1.obj1) {						System.out.println("Lock1 lock obj1");						Thread.sleep(3000);// 获取obj1后先等一会儿,让Lock2有足够的时间锁住obj2						synchronized (Demo1.obj2) {							System.out.println("Lock1 lock obj2");						}					}				}			} catch (Exception e) {				e.printStackTrace();			}			}		}		class Lock2 implements Runnable {			@Override		public void run() {			try {				System.out.println("Lock2 running");				while (true) {					synchronized (Demo1.obj2) {						System.out.println("Lock2 lock obj2");						Thread.sleep(3000);						synchronized (Demo1.obj1) {							System.out.println("Lock2 lock obj1");						}					}				}			} catch (Exception e) {				e.printStackTrace();			}			}		}

运行结果如下:

在这里插入图片描述

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

2.5.2 饥饿(Starvation)

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

2.5.3 活锁(Livelock)

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

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

如果觉得还不错,请点个赞!!!

Share Technology And Love Life

转载地址:http://oxbp.baihongyu.com/

你可能感兴趣的文章
mysql:SQL按时间查询方法总结
查看>>
MySQL:什么样的字段适合加索引?什么样的字段不适合加索引
查看>>
MySQL:判断逗号分隔的字符串中是否包含某个字符串
查看>>
MySQL:某个ip连接mysql失败次数过多,导致ip锁定
查看>>
MySQL:索引失效场景总结
查看>>
Mysql:避免重复的插入数据方法汇总
查看>>
MyS中的IF
查看>>
M_Map工具箱简介及地理图形绘制
查看>>
m_Orchestrate learning system---二十二、html代码如何变的容易
查看>>
M×N 形状 numpy.ndarray 的滑动窗口
查看>>
m个苹果放入n个盘子问题
查看>>
n = 3 , while n , continue
查看>>
n 叉树后序遍历转换为链表问题的深入探讨
查看>>
N!
查看>>
N-Gram的基本原理
查看>>
n1 c语言程序,全国青少年软件编程等级考试C语言经典程序题10道七
查看>>
Nacos Client常用配置
查看>>
nacos config
查看>>
Nacos Config--服务配置
查看>>
Nacos Derby 远程命令执行漏洞(QVD-2024-26473)
查看>>