《深入解析Android 5.0系统》——第6章,第6.3节Android Java层的同步机制

简介:

本节书摘来自异步社区《深入解析Android 5.0系统》一书中的第6章,第6.3节Android Java层的同步机制,作者 刘超,更多章节内容可以访问云栖社区“异步社区”公众号查看

6.3 Android Java层的同步机制
深入解析Android 5.0系统
Java语言和C/C++语言不一样,Java语言中提供了同步关键字synchronized来支持线程间的同步操作。

6.3.1 同步关键字synchronized
synchronized关键字最常见的用法是保护一段代码,如下所示:

class Foo implements Runnable

{

private String mLock;

public void lockedMethod()  { 

......
synchronized(**mL**ock) { ...... }

} 

......
}

synchronized还可以用在类的方法前面,如下所示:

class FooA implements Runnable

{

public **synchronized******void lockedMethod()  {  .....  }

public **synchronized******void unlockedockedMethod()  {  .....  } 
}

synchronize的第三种用法是修饰一个静态方法,如下所示:

class FooB implements Runnable

{

public **synchronized**** static **void lockedMethod() { ...... } 
}

这3种使用方法的含义有很大的区别。首先要理解,synchronize锁住的是对象,而不是一段代码。在Java中,每个对象都可以是一把锁,这意味着每个Java对象都有类似native层的Mutex对象的功能。而synchronize关键字则和native层的Autolock类似,起到的是自动加锁和解锁的作用。

对于上面介绍的第一种使用方法:使用synchronize保护一段代码,假设类Foo有两个实例对象foo1和foo2,如果在两个线程中分别调用fool.lockedMethod()方法,在同一时间,只有一个线程能执行被synchronize括起来的代码,也就起到了互斥作用。但是如果一个线程调用的是fool.lockedMethod(),另一个线程调用的是foo2.lockedMethod(),这样是不会互斥的。原因是对于前者,上锁的对象是foo1.mLock,后者上锁的对象是foo2.mLock,它们其实是两把完全不同的锁。

synchronize关键字的第二种用法:“用synchronize修饰一个非静态方法”,语法上等价于下面这种写法:

synchronized (this) {  ......  }

它表明上锁的对象是类的实例对象本身,而第一种用法中上锁的对象只是实例对象的成员变量,锁的范围扩大了。这样导致的结果是两个线程对于同一个实例对象的任何访问都将会互斥。具体而言:对于方法二中的例子,假定类FooA有一个实例对象foo_a,在两个线程中都访问foo_a.lockMethod()一定会互斥,一个线程访问foo_a.lockMethod(),另一个线程访问不同的函数foo_a.unlockedMethod()同样会互斥。当然如果是两个类实例对象foo_a和foo_b,分别调用它们的函数都不会互斥。

synchronize关键字的第三种用法:“用synchronize修饰一个静态的方法”,语法上等价于下面的写法:

synchronized (FooB.class) {  ......  }

它表明上锁的对象是类本身,这样锁的作用范围进一步扩大了。因此,导致的结果是一旦有一个线程调用的FooB类的任何实例对象的lockedMethod()方法,另一个线程对于FooB类的任何对象的lockedMethod()方法都将会将产生互斥。这种用法导致的结果是最严厉的。

从上面的介绍可以看到synchronized并不像表面看上去的那么简单,在一个函数内部使用synchronized关键字,有可能会导致对整个类的访问都被锁定(当然这样会显得比较晦涩)。可能也是这个原因,Java在语法上创造了用synchronize来修饰一个方法,这样至少看上去会更明显些。

6.3.2 Object类在同步中的作用
synchronized关键字只能提供互斥访问的同步机制,如果需要完成一些更复杂的同步操作,就需要Object类来配合完成。Object类是所有Java对象的基类,在Object类中提供了一些与同步相关的方法,如下所示:

public final native void notify();
public final native void notifyAll();
public final void wait();
public final void wait(long millis);
ublic final native void wait(long millis, int nanos);

同步相关的接口分为notify和wait两种类型,notify类型的函数用来唤醒挂起的线程,wait类型的函数用来挂起调用者所在的线程。

要注意的是,这些方法并不是随时随地都可以调用的,对它们的调用必须是在本线程取得对“Object对象”的控制权以后才能进行。更准确地说,应该在synchronized的作用域内调用。这可能有点不太好理解,下面来看一个使用Object对象做同步控制的例子,代码如下:

public class ObjectSync implements Runnable {
    private final static String Tag = "ObjectSync";
    private String name;
    private Object lock;
    private ObjectSync(String name, Object lock) {
        this.name = name;
        this.lock = lock;
    }
    @Override
    public void run() {
        int count = 10;
        while (count > 0) {
            synchronized (lock) {
                Log.i(Tag, name);
                lock.notify();
                try {
                    if(--count > 0) {
                        lock.wait();
                    }
                } catch (InterruptedException e) {
                    Log.e(Tag, e.getMessage());
                }
            }
        }
    }
    public static void output() {
        Object lock = new Object();
        Thread threadA = new Thread(new ObjectSync("A", lock));
        Thread threadB = new Thread(new ObjectSync("B", lock));
        threadA.start();
        threadB.start();
        try {
            threadA.join();
            threadB.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.i(Tag, "thread A & B are exited.");
    }
}

上面的例子中notify()和wait()都是在对lock对象操作,因此,它们必须在synchronized(lock)的代码块内调用,否则运行时会报异常。当然也可以把对notfiy()和wait()的调用放到一个方法内,然后在synchronized块内调用这个方法。

这个例子的目的是在两个线程中分别输出文字“A”和“B”,但是输出结果要是交替的,也是就“ABABAB”的形式。例子中output()方法是入口,它创建了一个Object对象lock作为锁,然后又创建了两个线程。两个线程用的是同一个线程类,但是用参数加以区别,并通过参数把lock对象传给了两个线程中,这样两个线程中将使用同一个对象锁。在线程的运行方法run()中,首先用synchronized关键字形成了一个临界区,进入临界区后,先打印输出,然后调用notify()方法,恢复对方线程的运行,再调用wait()使自己挂起,接着对方线程运行,打印结果后,再重复上面的过程。这样两个线程就交替运行起来了。

相关文章
|
3天前
|
JavaScript Java BI
Java毕设之新生报到系统的设计与实现
Java毕设之新生报到系统的设计与实现
11 3
|
2天前
|
Android开发
Android 如何将定制的Launcher成为系统中唯一的Launcher
Android 如何将定制的Launcher成为系统中唯一的Launcher
12 2
|
1天前
|
Java
排课系统【JSP+Servlet+JavaBean】(Java课设)
排课系统【JSP+Servlet+JavaBean】(Java课设)
13 5
|
1天前
|
存储 Java API
java对接IPFS系统-以nft.storage为列
java对接IPFS系统-以nft.storage为列
11 2
|
2天前
|
监控 前端开发 Java
Java基于B/S医院绩效考核管理平台系统源码 医院智慧绩效管理系统源码
医院绩效考核系统是一个关键的管理工具,旨在评估和优化医院内部各部门、科室和员工的绩效。一个有效的绩效考核系统不仅能帮助医院实现其战略目标,还能提升医疗服务质量,增强患者满意度,并促进员工的专业成长
9 0
|
2天前
|
XML JavaScript Java
详解Java解析XML的四种方法
详解Java解析XML的四种方法
|
2天前
|
Java 云计算
Java智能区域医院云HIS系统SaaS源码
云HIS提供标准化、信息化、可共享的医疗信息管理系统,实现医患事务管理和临床诊疗管理等标准医疗管理信息系统的功能。优化就医、管理流程,提升患者满意度、基层首诊率,通过信息共享、辅助诊疗等手段,提高基层医生的服务能力构建和谐的基层医患关系。
16 2
|
2天前
|
Java
解析java中的数组
解析java中的数组
10 3
|
2天前
|
监控 供应链 数据可视化
深度解析BPM系统:优化业务流程,提升组织效率
本文探讨了业务流程管理系统(BPM)的核心价值和功能,以及低代码如何优化流程管理。BPM通过自动化和标准化流程,提高效率,降低技术复杂性,促进协作和监控。低代码平台加速了开发进程,增强了流程自动化,使得非专业开发者也能构建应用程序。结合低代码,企业能更轻松地适应市场变化,实现流程简化和业务增长。
8 1
|
3天前
|
前端开发 Java 关系型数据库
Java医院绩效考核系统源码B/S架构+springboot三级公立医院绩效考核系统源码 医院综合绩效核算系统源码
作为医院用综合绩效核算系统,系统需要和his系统进行对接,按照设定周期,从his系统获取医院科室和医生、护士、其他人员工作量,对没有录入信息化系统的工作量,绩效考核系统设有手工录入功能(可以批量导入),对获取的数据系统按照设定的公式进行汇算,且设置审核机制,可以退回修正,系统功能强大,完全模拟医院实际绩效核算过程,且每步核算都可以进行调整和参数设置,能适应医院多种绩效核算方式。
21 2

推荐镜像

更多