博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
并发同步知多少
阅读量:6578 次
发布时间:2019-06-24

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

找工作的时候是否经常看到要求有高并发,分布式系统的开发设计经验,或者高并发,分布式系统的开发设计经验者优先等字样,这时候情不自禁的搜索一下 什么是并发,多少算高并发,再思索一下自己的经历哪些是符合这个要求的?那么什么是并发,开发中的并发是怎么处理的,简单了解一下吧。

        在介绍并发之前我们先了解一下串行和并行:

        热闹的景点,买票人很多,这时只有一个窗口售票,大家排队依次买票就可以理解为串行。

        排队人太多了,旁边又加开了几个窗口,多人在不同的窗口同时买票可以理解为并行。

        如果只能开一个窗口,这时好多着急的人围上来,有问价格的,有掏钱的,又有取票的,在这个过程中售票员在同时应对多个买票人,可以理解为并发。

        我们经常在计算机上一边听歌一边写文档(或者处理其他的事情),这就是一种并发行为,表面看两个程序是同时进行,为什么不是并行呢?计算机只有一个 CPU所以只能支持一个线程运行。有人拍砖说:我家里计算机是多核CPU可以同时支持多个线程运行,确实是这样,为此我也特地去百度了一下有如下几点认 知:

        1、虽然是多核CPU但是,系统总线,内存是共用的,在加载内存数据时仍然需要串行访问。

        2、目前的程序设计语言仍然是过程型开发,没有和好的方法能自动的切割任务使并行计算。

        3、操作系统在线程调度时随着内核的增加复杂性递增,目前最多支持8核

        所以基于以上认知,我们在讨论并发和同步这个问题时仍然按照CPU单核来讨论。

        那么计算机是如何做到一边播放歌曲一边支持文档编辑呢?操作系统会把CPU的执行时间划分微妙级别的时间片段,每一个时间片内去调度一个线程执行,多 个线程不断的切换执行,因此在人类可感知的时间段(秒级)内线程是同时执行的,所以多个线程在某个时间段内的同时执行就是并发。

串行、并行和并发如下图所示:

串行并行并发

        互联网应用基本上都是支持多用户多请求同时访问服务器端的,所以互联网应用都是支持并发的,那么高并发的主要困难是什么呢?操作系统会给每个线程分配 独立的内存空间和时间片,所以线程间是隔离的。但是如果线程访问线程外的内存空间,文件系统,输入输出设备,数据库或者其他存储设备时就会发生资源竞争, 共享资源的访问必须串行,保证串行访问资源的机制就是同步,JAVA中经常使用的同步机制有synchronized关键字,java.util.concurrent.locks.Lock系列类。

  同步的场景有以下几种:

  1、线程获取同步锁,获取失败则阻塞等待

同步1

  适用场景:

  a、同步获取序列号生成器,当有其他线程获取序列号时,其他线程等待

  java代码实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public
class
SynchronizedProcessor
implements
Processor {
  
    
/* (non-Javadoc)
     
* @see com.sunhaojie.test.thread.Processor#process(java.lang.String)
     
*/
    
public
void
process(String name) {
        
System.out.println(String.format(
"%s开始处理,当前时间是%d"
, name,
System.currentTimeMillis()));
        
synchronized
(
this
) {
            
System.out.println(String.format(
"%s获得锁%s"
, name,
this
.toString()));
            
try
{
                
System.out.println(String.format(
"%s开始sleep"
, name));
                
Thread.sleep(
1000
);
                
System.out.println(String.format(
"%s结束sleep"
, name));
            
}
catch
(InterruptedException e) {
                
e.printStackTrace();
            
}
        
}
        
System.out.println(String.format(
"%s释放锁%s"
, name,
this
.toString()));
        
System.out.println(String.format(
"%s结束处理,当前时间是%d"
, name,
System.currentTimeMillis()));
    
}
  
}

  2、线程获取同步锁,获取失败结束

同步2

  适用场景:

  a、定时任务,前一个处理线程未完成时,新线程不能获取锁则直接结束

  java代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public
class
LockFailCloseProcessor
implements
Processor {
    
private
static
Lock lock =
new
ReentrantLock();
  
    
/* (non-Javadoc)
     
* @see com.sunhaojie.test.thread.Processor#process(java.lang.String)
     
*/
    
public
void
process(String name) {
        
System.out.println(String.format(
"%s开始处理,当前时间是%d"
, name,
System.currentTimeMillis()));
        
if
(lock.tryLock()) {
            
System.out.println(String.format(
"%s获得锁%s"
, name,
this
.toString()));
            
try
{
                
System.out.println(String.format(
"%s开始sleep"
, name));
                
Thread.sleep(
1000
);
                
System.out.println(String.format(
"%s结束sleep"
, name));
            
}
catch
(InterruptedException e) {
                
e.printStackTrace();
            
}
            
lock.unlock();
            
System.out.println(String.format(
"%s释放锁%s"
, name,
this
.toString()));
        
}
else
{
            
System.out.println(String.format(
"%s没有获得锁直接退出"
,
name));
        
}
        
System.out.println(String.format(
"%s结束处理,当前时间是%d"
, name,
System.currentTimeMillis()));
    
}
}

  3、线程获取同步锁后,因为其他资源不满足暂时释放同步锁,等待唤醒

同步3

  适用场景:

  a、即使通讯中,发送者获取同步锁发现队列写满时,释放锁等待接收者读取数据

  java代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public
class
SynchronizedWaitWriteProcessor
implements
Processor {
  
    
/**
     
* 是否可读标记,false:不可读,可写 true:可读,不可写
     
*/
    
public
static
int
maxSize =
5
;
    
public
static
List<String> content =
new
ArrayList<String>();
  
    
/* (non-Javadoc)
     
* @see com.sunhaojie.test.thread.Processor#process(java.lang.String)
     
*/
    
public
void
process(String name) {
        
System.out.println(String.format(
"%s开始处理,当前时间是%d"
, name,
System.currentTimeMillis()));
        
synchronized
(content) {
            
System.out.println(String.format(
"%s获得锁%s"
, name,
this
.toString()));
            
try
{
                
if
(content.size() == maxSize) {
                    
System.out.println(
String.format(
"%s临时释放锁%s"
, name,
this
.toString()));
                    
content.wait();
                
}
                
System.out.println(
String.format(
"%s开始写入信息"
, name));
                
Random random =
new
Random();
                
for
(
int
i =
0
; i < maxSize; i++) {
                    
content.add(
String.format(
"写入信息%d"
, random.nextInt(
1000
)));
                
}
                
System.out.println(
String.format(
"%s结束写入信息"
, name));
            
}
catch
(InterruptedException e) {
                
e.printStackTrace();
            
}
            
content.notify();
        
}
        
System.out.println(String.format(
"%s释放锁%s"
, name,
this
.toString()));
        
System.out.println(String.format(
"%s结束处理,当前时间是%d"
, name,
System.currentTimeMillis()));
    
}
  
}

  4、线程获取同步锁后,因为其他资源不满足结束线程

  适用场景:

同步4

  a、即使通讯中,接收者获取同步锁发现队列无数据时,释放锁结束线程

  java代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public
class
SynchronizedWaitReadProcessor
implements
Processor {
  
    
/* (non-Javadoc)
     
* @see com.sunhaojie.test.thread.Processor#process(java.lang.String)
     
*/
    
public
void
process(String name) {
        
System.out.println(String.format(
"%s开始处理,当前时间是%d"
, name,
System.currentTimeMillis()));
        
synchronized
(SynchronizedWaitWriteProcessor.content) {
            
System.out.println(String.format(
"%s获得锁%s"
, name,
this
.toString()));
            
if
(SynchronizedWaitWriteProcessor.content.size()
!=
0
) {
                
System.out.println(
String.format(
"%s开始读出信息"
, name));
                
for
(
int
i =
0
;
i < SynchronizedWaitWriteProcessor.content.size(); i++) {
                    
System.out.println(
"读出信息:"
+ SynchronizedWaitWriteProcessor.content.get(i));
                
}
                
System.out.println(
String.format(
"%s结束读出信息"
, name));
            
}
            
SynchronizedWaitWriteProcessor.content.notify();
        
}
        
System.out.println(String.format(
"%s释放锁%s"
, name,
this
.toString()));
        
System.out.println(String.format(
"%s结束处理,当前时间是%d"
, name,
System.currentTimeMillis()));
    
}
  
}

  最后送上运行以上程序的main方法和Processor 接口类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public
interface
Processor {
    
public
void
process(String name);
}
public
class
ThreadTest {
  
    
public
static
void
main(String[] args)
throws
InterruptedException {
        
//测试SynchronizedProcessor
        
//        Processor processor = new SynchronizedProcessor();
        
//        for (int i = 0; i < 10; i++) {
        
//            ProcessorThread threadProcessor =
new
ProcessorThread(
"name"
+ i, processor);
        
//            threadProcessor.start();
        
//        }
  
        
//测试LockProcessor
        
//        Processor processor = new LockProcessor();
        
//        for (int i = 0; i < 10; i++) {
        
//            ProcessorThread threadProcessor =
new
ProcessorThread(
"name"
+ i, processor);
        
//            threadProcessor.start();
        
//        }
  
        
// Processor processor = new LockFailCloseProcessor();
        
// for (int i = 0; i < 10; i++) {
        
// ProcessorThread threadProcessor =
new
ProcessorThread(
"name"
+ i,
        
// processor);
        
// threadProcessor.start();
        
// }
  
        
Processor readProcessor =
new
SynchronizedWaitReadProcessor();
        
ProcessorThread readThreadProcessor =
new
ProcessorThread(
"read"
, readProcessor);
        
readThreadProcessor.start();
        
Processor writeProcessor =
new
SynchronizedWaitWriteProcessor();
        
ProcessorThread writeThreadProcessor =
new
ProcessorThread(
"write"
, writeProcessor);
        
writeThreadProcessor.start();
        
Thread.sleep(
100
);
        
ProcessorThread read2ThreadProcessor =
new
ProcessorThread(
"read2"
, readProcessor);
        
read2ThreadProcessor.start();
    
}
}

  多线程可以大大提高性能,但是多线程的同步又增加了应用的复杂性,是否能平衡多线程的性能和复杂性是是否有高并发经验的要求。

转载于:https://www.cnblogs.com/chinway/p/5534610.html

你可能感兴趣的文章
[清华集训2014]玛里苟斯
查看>>
【MVC+EasyUI实例】对数据网格的增删改查(上)
查看>>
Project Euler 345: Matrix Sum
查看>>
你可能不知道的技术细节:存储过程参数传递的影响
查看>>
[摘录]调动员工积极性的七个关键
查看>>
.htaccess 基础教程(四)Apache RewriteCond 规则参数
查看>>
Android控件之HorizontalScrollView 去掉滚动条
查看>>
UVM中的class--2
查看>>
ORACLE 存储过程异常捕获并抛出
查看>>
root用户重置其他密码
查看>>
Oracle推断值为非数字
查看>>
多年前写的一个ASP.NET网站管理系统,到现在有些公司在用
查看>>
vue-cli中理不清的assetsSubDirectory 和 assetsPublicPath
查看>>
从JDK源码角度看Short
查看>>
五年 Web 开发者 star 的 github 整理说明
查看>>
Docker 部署 SpringBoot 项目整合 Redis 镜像做访问计数Demo
查看>>
中台之上(五):业务架构和中台的难点,都是需要反复锤炼出标准模型
查看>>
使用模板将Web服务的结果转换为标记语言
查看>>
inno setup 打包脚本学习
查看>>
php 并发控制中的独占锁
查看>>