浅谈synchronized关键字在Android的应用

进程和线程

在操作系统的学习中,讲到过“进程”(Process)和“线程”(Thread)两种概念,关于其由来笔者在这里不做探讨,首先要说的是进程和线程的一些相同和不同

其实从计算机的底层本质来说,一个进程和一个线程在内存空间上没有什么区别,都是载入,分配,然后做你自己的事情

在“线程”还未诞生的年代,计算机都以“进程”为最小的调度单元,程序都是单线程形式;随着时代发展,人们对计算机的实时性要求越来越高,单线程的工作效率已经不能满足市场需求,于是“线程”便诞生了。它取代“进程”成为了最小的调度单元,而“进程”则成为了最小的内存分配单位

在之前,当我们打开一个应用程序,进程要逐步处理程序的初始化,界面描绘等等一系列操作,这些都交给进程以串行的方式去运作,甚至于在做网络请求、下载多个文件时,也是一个一个去下载。但当有了线程之后,进程则从底层的工人升级为了包工头——它开始将自己原本的工作分给一个个线程去做,而进程只需要负责进行调度和接收回调

一个应用程序对应一个进程,其中可以包含多数个线程,而这些线程都能被分配到CPU的每个核上与运作

为什么要使用线程?

使用多线程的优势在于:现在CPU的发展趋势从提高核心频率转向了增加核心数量,在多核CPU架构下多线程更能高效利用到CPU的计算资源,同时也提高了程序运行效率

在Android开发中的应用

不离本行,我们要如何在Android开发中运用到多线程开发呢?

首先想象一下运用场景……

笔者概括为:操作数据的时候

是的,在我们对数据进行读写时,经常会遇到在一个极短暂的时间段内对同一块数据进行并发地读写。比如在使用sqlite数据库对本地数据进行读写操作时,获取后台数据,发送数据到后台写入时等等……

就笔者开发过的项目中,遇到过类似的问题。因为该项目量级不重,我们需要缓存在本地的数据就是n个JSONString,为此,开发队伍并没有使用sqlite而是使用了sharedpreferences来存放本地数据,格式如下:

key value
root [address1, address2, address3……]
address1 JSONString1
address2 JSONString2
…… ……

每次将一条缓存数据发送至后台,后台回复确认收到之后将对应key-address删除,然后重写root

问题就出现在重写root这里,并行池限定容量5,同时创建5个线程发送address1、address2、address3、address4、address5的数据,但是对root的操作是“先将root读出–>删去对应的address–>写回”,这样就可能会导致以下问题:

线程1操作 线程2操作
读入root
发送数据 读入root
发送数据
得到回复确认 得到回复确认
从root中删去address1 从root中删去address2
写回
写回

发现了什么问题吗?

当线程2结束时写回的root中依然存在address1!

synchronized

先把上述问题的解决办法放到一边,笔者首先谈一下synchronized这个关键字

对于java来说,最常用的同步机制就是synchronized关键字,这是一种基于语言的粗略锁,能够作用于对象、函数、class。每个对象都只有一个锁,谁能够拿到这个锁谁就有访问权限。当synchronized作用于函数时,实际上锁的也是对象,锁定的对象就是该函数所在类的对象。而synchronized作用于class时则是锁的这个class类,并非具体对象

根据不同的写法,synchronized可以为一个具体的对象,或者其内的某个方法加锁,当有多个线程需要调用这个对象时,则会按照FIFO的方式进行调度等待操作;synchronized也可以作用于一个类,作用域更广,所有这个类的实例对象都会受到同一把锁的限制

我们可以为对象的一个方法加锁:

public synchronized void f(){}

也可以为对象的一段代码块加锁:

synchronized (this){}

也可以为类的static方法加锁:

public synchronized static void staticF(){}

也可以为类的代码块加锁:

synchronized (SynchronizedClass.class){}

前2种锁的是对象,而后两种锁的是class。对于class来说,它的作用是防止多个线程同时访问添加了synchronized锁的代码块,而synchronized作用于对象是防止其他线程访问同一个对象中synchronized代码块或者函数。

基于synchronized的解决方案

铺垫了这么多,其实解决的方式很简单,把sharedpreferences操作封装成类然后给它加锁就好啦

(璐出贾笑)

猜你喜欢

转载自blog.csdn.net/qq_16634723/article/details/80040952