精华内容
下载资源
问答
  • 1.什么是Java内存模型?...类的状态,也就是类之间共享的变量,是存储在主内存中的,每次Java线程用到这些主内存中的变量的时候,会读一内存中的变量,并让这些内存在自己的工作内存中有一份拷贝,运行...

    1.什么是Java内存模型?

    Java内存模型定义了一种多线程访问Java内存的规范。Java内存模型要完整讲不是这里几句话能说清楚的,我简单总结一下Java内存模型的几部分内容:

    (1)Java内存模型将内存分为了主内存和工作内存。类的状态,也就是类之间共享的变量,是存储在主内存中的,每次Java线程用到这些主内存中的变量的时候,会读一次主内存中的变量,并让这些内存在自己的工作内存中有一份拷贝,运行自己线程代码的时候,用到这些变量,操作的都是自己工作内存中的那一份。在线程代码执行完毕之后,会将最新的值更新到主内存中去。

    (2)定义了几个原子操作,用于操作主内存和工作内存中的变量。

    (3)定义了volatile变量的使用规则。

    (4)happens-before,即先行发生原则,定义了操作A必然先行发生于操作B的一些规则,比如在同一个线程内控制流前面的代码一定先行发生于控制流后面的代码、一个释放锁unlock的动作一定先行发生于后面对于同一个锁进行锁定lock的动作等等,只要符合这些规则,则不需要额外做同步措施,如果某段代码不符合所有的happens-before规则,则这段代码一定是线程非安全的。

    展开全文
  • 31、什么是Java内存模型Java内存...类的状态,也就是类之间共享的变量,是存储在主内存中的,每次Java线程用到这些主内存中的变量的时候,会读一内存中的变量,并让这些内存在自己的工作内存中有一份拷贝,运行...

    31、什么是Java内存模型

    Java内存模型定义了一种多线程访问Java内存的规范。Java内存模型要完整讲不是这里几句话能说清楚的,我简单总结一下Java内存模型的几部分内容:

    (1)Java内存模型将内存分为了主内存和工作内存。类的状态,也就是类之间共享的变量,是存储在主内存中的,每次Java线程用到这些主内存中的变量的时候,会读一次主内存中的变量,并让这些内存在自己的工作内存中有一份拷贝,运行自己线程代码的时候,用到这些变量,操作的都是自己工作内存中的那一份。在线程代码执行完毕之后,会将最新的值更新到主内存中去

    (2)定义了几个原子操作,用于操作主内存和工作内存中的变量

    (3)定义了volatile变量的使用规则

    (4)happens-before,即先行发生原则,定义了操作A必然先行发生于操作B的一些规则,比如在同一个线程内控制流前面的代码一定先行发生于控制流后面的代码、一个释放锁unlock的动作一定先行发生于后面对于同一个锁进行锁定lock的动作等等,只要符合这些规则,则不需要额外做同步措施,如果某段代码不符合所有的happens-before规则,则这段代码一定是线程非安全的

    32、什么是CAS

    CAS,全称为Compare and Set,即比较-设置。假设有三个操作数:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,才会将内存值修改为B并返回true,否则什么都不做并返回false。当然CAS一定要volatile变量配合,这样才能保证每次拿到的变量是主内存中最新的那个值,否则旧的预期值A对某条线程来说,永远是一个不会变的值A,只要某次CAS操作失败,永远都不可能成功。

    33、什么是乐观锁和悲观锁

    (1)乐观锁:就像它的名字一样,对于并发间操作产生的线程安全问题持乐观状态,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将比较-设置这两个动作作为一个原子操作尝试去修改内存中的变量,如果失败则表示发生冲突,那么就应该有相应的重试逻辑。

    (2)悲观锁:还是像它的名字一样,对于并发间操作产生的线程安全问题持悲观状态,悲观锁认为竞争总是会发生,因此每次对某资源进行操作时,都会持有一个独占的锁,就像synchronized,不管三七二十一,直接上了锁就操作资源了。

    34、什么是AQS

    简单说一下AQS,AQS全称为AbstractQueuedSychronizer,翻译过来应该是抽象队列同步器。

    如果说java.util.concurrent的基础是CAS的话,那么AQS就是整个Java并发包的核心了,ReentrantLock、CountDownLatch、Semaphore等等都用到了它。AQS实际上以双向队列的形式连接所有的Entry,比方说ReentrantLock,所有等待的线程都被放在一个Entry中并连成双向队列,前面一个线程使用ReentrantLock好了,则双向队列实际上的第一个Entry开始运行。

    AQS定义了对双向队列所有的操作,而只开放了tryLock和tryRelease方法给开发者使用,开发者可以根据自己的实现重写tryLock和tryRelease方法,以实现自己的并发功能。

    35、单例模式的线程安全性

    老生常谈的问题了,首先要说的是单例模式的线程安全意味着:某个类的实例在多线程环境下只会被创建一次出来。单例模式有很多种的写法,我总结一下:

    (1)饿汉式单例模式的写法:线程安全

    (2)懒汉式单例模式的写法:非线程安全

    (3)双检锁单例模式的写法:线程安全

    36、Semaphore有什么作用

    Semaphore就是一个信号量,它的作用是限制某段代码块的并发数。Semaphore有一个构造函数,可以传入一个int型整数n,表示某段代码最多只有n个线程可以访问,如果超出了n,那么请等待,等到某个线程执行完毕这段代码块,下一个线程再进入。由此可以看出如果Semaphore构造函数中传入的int型整数n=1,相当于变成了一个synchronized了。

    37、Hashtable的size()方法中明明只有一条语句”return count”,为什么还要做同步?

    这是我之前的一个困惑,不知道大家有没有想过这个问题。某个方法中如果有多条语句,并且都在操作同一个类变量,那么在多线程环境下不加锁,势必会引发线程安全问题,这很好理解,但是size()方法明明只有一条语句,为什么还要加锁?

    关于这个问题,在慢慢地工作、学习中,有了理解,主要原因有两点:

    (1)同一时间只能有一条线程执行固定类的同步方法,但是对于类的非同步方法,可以多条线程同时访问。所以,这样就有问题了,可能线程A在执行Hashtable的put方法添加数据,线程B则可以正常调用size()方法读取Hashtable中当前元素的个数,那读取到的值可能不是最新的,可能线程A添加了完了数据,但是没有对size++,线程B就已经读取size了,那么对于线程B来说读取到的size一定是不准确的。而给size()方法加了同步之后,意味着线程B调用size()方法只有在线程A调用put方法完毕之后才可以调用,这样就保证了线程安全性

    (2)CPU执行代码,执行的不是Java代码,这点很关键,一定得记住。Java代码最终是被翻译成汇编代码执行的,汇编代码才是真正可以和硬件电路交互的代码。即使你看到Java代码只有一行,甚至你看到Java代码编译之后生成的字节码也只有一行,也不意味着对于底层来说这句语句的操作只有一个。一句”return count”假设被翻译成了三句汇编语句执行,完全可能执行完第一句,线程就切换了。

    38、线程类的构造方法、静态块是被哪个线程调用的

    这是一个非常刁钻和狡猾的问题。请记住:线程类的构造方法、静态块是被new这个线程类所在的线程所调用的,而run方法里面的代码才是被线程自身所调用的。

    如果说上面的说法让你感到困惑,那么我举个例子,假设Thread2中new了Thread1,main函数中new了Thread2,那么:

    (1)Thread2的构造方法、静态块是main线程调用的,Thread2的run()方法是Thread2自己调用的

    (2)Thread1的构造方法、静态块是Thread2调用的,Thread1的run()方法是Thread1自己调用的

    39、同步方法和同步块,哪个是更好的选择

    同步块,这意味着同步块之外的代码是异步执行的,这比同步整个方法更提升代码的效率。请知道一条原则:同步的范围越少越好。

    借着这一条,我额外提一点,虽说同步的范围越少越好,但是在Java虚拟机中还是存在着一种叫做锁粗化的优化方法,这种方法就是把同步范围变大。这是有用的,比方说StringBuffer,它是一个线程安全的类,自然最常用的append()方法是一个同步方法,我们写代码的时候会反复append字符串,这意味着要进行反复的加锁->解锁,这对性能不利,因为这意味着Java虚拟机在这条线程上要反复地在内核态和用户态之间进行切换,因此Java虚拟机会将多次append方法调用的代码进行一个锁粗化的操作,将多次的append的操作扩展到append方法的头尾,变成一个大的同步块,这样就减少了加锁–>解锁的次数,有效地提升了代码执行的效率。

    40、高并发、任务执行时间短的业务怎样使用线程池?并发不高、任务执行时间长的业务怎样使用线程池?并发高、业务执行时间长的业务怎样使用线程池?

    这是我在并发编程网上看到的一个问题,把这个问题放在最后一个,希望每个人都能看到并且思考一下,因为这个问题非常好、非常实际、非常专业。关于这个问题,个人看法是:

    (1)高并发、任务执行时间短的业务,线程池线程数可以设置为CPU核数+1,减少线程上下文的切换

    (2)并发不高、任务执行时间长的业务要区分开看:

    a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以加大线程池中的线程数目,让CPU处理更多的业务

    b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换

    (3)并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,设置参考(2)。最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件对任务进行拆分和解耦。

    展开全文
  • 线程系列问题:四

    2020-03-20 10:01:41
    什么是Java内存模型 ...类的状态,也就是类之间共享的变量,是存储在主内存中的,每次Java线程用到这些主内存中的变量的时候,会读一内存中的变量,并让这些内存在自己的工作内存中有一份拷贝,运行自...

    什么是Java内存模型

    Java内存模型定义了一种多线程访问Java内存的规范。Java内存模型要完整讲不是这里几句话能说清楚的,我简单总结一下Java内存模型的几部分内容:

    (1)Java内存模型将内存分为了主内存和工作内存。类的状态,也就是类之间共享的变量,是存储在主内存中的,每次Java线程用到这些主内存中的变量的时候,会读一次主内存中的变量,并让这些内存在自己的工作内存中有一份拷贝,运行自己线程代码的时候,用到这些变量,操作的都是自己工作内存中的那一份。在线程代码执行完毕之后,会将最新的值更新到主内存中去

    (2)定义了几个原子操作,用于操作主内存和工作内存中的变量

    (3)定义了volatile变量的使用规则

    (4)happens-before,即先行发生原则,定义了操作A必然先行发生于操作B的一些规则,比如在同一个线程内控制流前面的代码一定先行发生于控制流后面的代码、一个释放锁unlock的动作一定先行发生于后面对于同一个锁进行锁定lock的动作等等,只要符合这些规则,则不需要额外做同步措施,如果某段代码不符合所有的happens-before规则,则这段代码一定是线程非安全的

    32、什么是CAS

    CAS,全称为Compare and Set,即比较-设置。假设有三个操作数:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,才会将内存值修改为B并返回true,否则什么都不做并返回false。当然CAS一定要volatile变量配合,这样才能保证每次拿到的变量是主内存中最新的那个值,否则旧的预期值A对某条线程来说,永远是一个不会变的值A,只要某次CAS操作失败,永远都不可能成功。

    33、什么是乐观锁和悲观锁

    (1)乐观锁:就像它的名字一样,对于并发间操作产生的线程安全问题持乐观状态,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将比较-设置这两个动作作为一个原子操作尝试去修改内存中的变量,如果失败则表示发生冲突,那么就应该有相应的重试逻辑。

    (2)悲观锁:还是像它的名字一样,对于并发间操作产生的线程安全问题持悲观状态,悲观锁认为竞争总是会发生,因此每次对某资源进行操作时,都会持有一个独占的锁,就像synchronized,不管三七二十一,直接上了锁就操作资源了。

    34、什么是AQS

    简单说一下AQS,AQS全称为AbstractQueuedSychronizer,翻译过来应该是抽象队列同步器。

    如果说java.util.concurrent的基础是CAS的话,那么AQS就是整个Java并发包的核心了,ReentrantLock、CountDownLatch、Semaphore等等都用到了它。AQS实际上以双向队列的形式连接所有的Entry,比方说ReentrantLock,所有等待的线程都被放在一个Entry中并连成双向队列,前面一个线程使用ReentrantLock好了,则双向队列实际上的第一个Entry开始运行。

    AQS定义了对双向队列所有的操作,而只开放了tryLock和tryRelease方法给开发者使用,开发者可以根据自己的实现重写tryLock和tryRelease方法,以实现自己的并发功能。

    35、单例模式的线程安全性

    老生常谈的问题了,首先要说的是单例模式的线程安全意味着:某个类的实例在多线程环境下只会被创建一次出来。单例模式有很多种的写法,我总结一下:

    (1)饿汉式单例模式的写法:线程安全

    (2)懒汉式单例模式的写法:非线程安全

    (3)双检锁单例模式的写法:线程安全

    36、Semaphore有什么作用

    Semaphore就是一个信号量,它的作用是限制某段代码块的并发数。Semaphore有一个构造函数,可以传入一个int型整数n,表示某段代码最多只有n个线程可以访问,如果超出了n,那么请等待,等到某个线程执行完毕这段代码块,下一个线程再进入。由此可以看出如果Semaphore构造函数中传入的int型整数n=1,相当于变成了一个synchronized了。

    37、Hashtable的size()方法中明明只有一条语句”return count”,为什么还要做同步?

    这是我之前的一个困惑,不知道大家有没有想过这个问题。某个方法中如果有多条语句,并且都在操作同一个类变量,那么在多线程环境下不加锁,势必会引发线程安全问题,这很好理解,但是size()方法明明只有一条语句,为什么还要加锁?

    关于这个问题,在慢慢地工作、学习中,有了理解,主要原因有两点:

    (1)同一时间只能有一条线程执行固定类的同步方法,但是对于类的非同步方法,可以多条线程同时访问。所以,这样就有问题了,可能线程A在执行Hashtable的put方法添加数据,线程B则可以正常调用size()方法读取Hashtable中当前元素的个数,那读取到的值可能不是最新的,可能线程A添加了完了数据,但是没有对size++,线程B就已经读取size了,那么对于线程B来说读取到的size一定是不准确的。而给size()方法加了同步之后,意味着线程B调用size()方法只有在线程A调用put方法完毕之后才可以调用,这样就保证了线程安全性

    (2)CPU执行代码,执行的不是Java代码,这点很关键,一定得记住。Java代码最终是被翻译成汇编代码执行的,汇编代码才是真正可以和硬件电路交互的代码。即使你看到Java代码只有一行,甚至你看到Java代码编译之后生成的字节码也只有一行,也不意味着对于底层来说这句语句的操作只有一个。一句”return count”假设被翻译成了三句汇编语句执行,完全可能执行完第一句,线程就切换了。

    38、线程类的构造方法、静态块是被哪个线程调用的

    这是一个非常刁钻和狡猾的问题。请记住:线程类的构造方法、静态块是被new这个线程类所在的线程所调用的,而run方法里面的代码才是被线程自身所调用的。

    如果说上面的说法让你感到困惑,那么我举个例子,假设Thread2中new了Thread1,main函数中new了Thread2,那么:

    (1)Thread2的构造方法、静态块是main线程调用的,Thread2的run()方法是Thread2自己调用的

    (2)Thread1的构造方法、静态块是Thread2调用的,Thread1的run()方法是Thread1自己调用的

    39、同步方法和同步块,哪个是更好的选择

    同步块,这意味着同步块之外的代码是异步执行的,这比同步整个方法更提升代码的效率。请知道一条原则:同步的范围越少越好。

    借着这一条,我额外提一点,虽说同步的范围越少越好,但是在Java虚拟机中还是存在着一种叫做锁粗化的优化方法,这种方法就是把同步范围变大。这是有用的,比方说StringBuffer,它是一个线程安全的类,自然最常用的append()方法是一个同步方法,我们写代码的时候会反复append字符串,这意味着要进行反复的加锁->解锁,这对性能不利,因为这意味着Java虚拟机在这条线程上要反复地在内核态和用户态之间进行切换,因此Java虚拟机会将多次append方法调用的代码进行一个锁粗化的操作,将多次的append的操作扩展到append方法的头尾,变成一个大的同步块,这样就减少了加锁–>解锁的次数,有效地提升了代码执行的效率。

    40、高并发、任务执行时间短的业务怎样使用线程池?并发不高、任务执行时间长的业务怎样使用线程池?并发高、业务执行时间长的业务怎样使用线程池?

    这是我在并发编程网上看到的一个问题,把这个问题放在最后一个,希望每个人都能看到并且思考一下,因为这个问题非常好、非常实际、非常专业。关于这个问题,个人看法是:

    (1)高并发、任务执行时间短的业务,线程池线程数可以设置为CPU核数+1,减少线程上下文的切换

    (2)并发不高、任务执行时间长的业务要区分开看:

    a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以加大线程池中的线程数目,让CPU处理更多的业务

    b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换

    (3)并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,设置参考(2)。最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件对任务进行拆分和解耦。

    展开全文
  • Android进程间通信

    2019-12-21 22:21:19
    一、常见通信方式梳理 进程间常见的通信方式有以下种: 1、Socket:通用接口,传输效率低,主要用在跨网络通信和本机进程间通信,传输过程需要拷贝2数据; 2、共享内存:虽然无需拷贝... 共享内存:适合效率...

    一、常见通信方式梳理
    进程间常见的通信方式有以下几种:
    1、Socket:通用接口,传输效率低,主要用在跨网络通信和本机进程间通信,传输过程需要拷贝2次数据;
    2、共享内存:虽然无需拷贝,但控制复杂;
    3、Binder:基于C/S模式,只需1次拷贝,安全性高。

    不同的通信方式使用场景也不同:

    •    Socket:适合网络间的通信,或者效率要求不高的本机进程间通信;
    •    共享内存:适合效率要求较高的底层进程间通信;
    •    Binder:兼顾效率和安全性的进程间通信,需要返回结果;
    •    Messenger:低并发的、一对多的进程间通信,无需返回结果。

    二、 Binder和AIDL
    1、Binder机制浅析

    Binder机制,整体上基于C/S架构实现,客户端先获取远程服务端的对象引用,通过该引用调用远程函数,然后由Binder驱动找到对应的服务端函数再执行。其设计初衷是,降低使用复杂度、改善安全性、并提高传输效率。

    其中的Binder驱动,是作为一个特殊字符型设备存在,设备节点为/dev/binder,遵循Linux设备驱动模型。在驱动实现过程中,系统主要通过 binder_ioctl 函数与用户空间的进程交换数据。binder_thread_write函数用于发送请求或返回结果,而binder_thread_read函数用于读取结果。

    2、AIDL
    AIDL本质是系统提供的一套可快速实现Binder调用的工具/语言,其中工具也就是aidl.exe,可将aidl文件转为java文件,语言就是aidl文件使用的接口描述语言,用于.aidl文件。

    1)关键类和方法

    • asInterface():AIDL接口中的一个方法,提供客户端调用。该方法可以将服务端的返回的Binder对象或BinderProxy对象,转换成客户端所需要的AIDL接口类型对象(一个Stub.Proxy实例)。
    • Proxy类:服务端在客户端进程的代理类。客户端通过Binder对象的asInterface方法获取Proxy实例,再通过该实例调用服务端的自定义方法。
    • transact()方法:运行在客户端。客户端调用具体功能方法时,需要在接口类中,通过BinderProxy类型的mRemote对象的transact方法发起远程请求,同时将当前线程挂起,直到远程请求返回才继续执行。
    • AIDL接口:继承android.os.IInterface,由客户端的aidl文件通过编译自动生成。例如IActivityManager这个接口就是由IActivityManager.aidl自动生成的(客户端和服务端都有)。
    • Stub类:Binder的实现类。服务端通过这个类来提供服务。注意是抽象类,其static方法asInterface给客户端调用,其他方法给系统调用,最终会调用到具体实现(一般在Stub的实例对象中)
    • onTransact()方法:运行在服务端的Binder线程池中,当客户端发起transact跨进程请求时,系统回调此方法处理请求。

    补充,transact调用中的code参数,一般对应具体的功能,类似index,一个Binder对象使用的code值,在应用内部必须能够区分,但不同的Binder对象使用的code值可以重复。

    在服务端进程中,有个Stub类,这个是Binder的实现类,服务端通过这个类来提供服务。注意该类是抽象类,其static方法asInterface给客户端调用,其他方法给系统调用,最终会调用到具体实现(一般在Stub的实例对象中), 其onTransact()方法运行在服务端的Binder线程池中,当客户端发起transact跨进程请求时,系统回调此方法处理请求)。

    在客户端进程中,asInterface()是AIDL接口中的一个方法,提供客户端调用。该方法可以将服务端的返回的Binder对象或BinderProxy对象,转换成客户端所需要的AIDL接口类型对象(一个Stub.Proxy实例)。

    2)代理类的设计
    BinderProxy是Android系统用于跨进程通信、访问远程服务中的Binder实例对象而设计的,侧重系统调用,对用户不透明。实际上它是在native层javaObjectForIBinder方法中创建的,属于客户端进程中的对象,和Native层的BpBinder有对应关系。
    形如IxxxService.Stub.Proxy这种代理类,用于跨进程通信、访问远程服务中的用户自定义方法而设计的,侧重应用层,实际上该类基本都是通过其实现的AIDL接口例如IActivityManager来调用。
    对于Service组件的远程绑定,BinderProxy与Binder实例(比如IxxxService.Stub类型的变量mBinder)的映射关系,是通过BinderProxy.ProxyMap这个类维护的。而IxxxService.Stub.Proxy实例与Binder实例(IxxxService.Stub类型的变量mBinder)的映射关系,是通过Proxy类的构造函数及其成员变量mRemote维护的,这里mRemote就是mBinder在客户端进程的代理也就是BinderProxy对象。
    如果我们获取到Proxy类的实例,可以调用其asBinder方法获取该实例维护的BinderProxy对象,反过来也可以通过BinderProxy实例的asInterface方法来获取Proxy对象。

    三、 融合与思考
    1、Binder常见使用场景解析
    场景1:绑定服务,例如WallpaperService,其代理对象所需的BinderProxy实例(远程服务时),是onServiceConnected回调参数中IBinder类型的service。

    场景2:系统服务,例如AMS、WMS等,其代理对象所需的BinderProxy实例,是通过ServiceManager.getService方法调用返回的对象。

    场景3:间接访问核心组件,例如IWindowSession。IWindowSession的实现类是Session,不属于服务。客户端例如WindowManagerGlobal,先通过ServiceManager获取WMS的本地代理也就是IWindowManager的实例,再利用此代理的openSession方法得到Session的本地代理IWindowSession。

    Binder跨进程通信的关键,是一个实现了IBinder接口的对象,该对象可用于调用远程服务的本地Binder类的asInterface方法,获得远程类的本地代理。如前所述,获得IBinder对象的途径有3种以上,包括利用ServiceConnection回调(绑定服务)直接获得;或者利用ServiceManager(系统服务)直接获得;或者通过别的代理(基于系统服务或绑定服务)对象的某些方法间接获得。

    除了上面3种场景,还有一种特殊情况:IServiceManger。该类派生于android.os.IInterface,定义了用于实现具体功能的接口,例如addService、getService。

    ServiceManagerNative派生于Binder,作为远程ServiceManager的本地Binder类,提供asInterface方法(对应工具自动生成的java类中的IxxService.Stub)。ServiceManagerProxy是远程ServiceManager的本地代理类,提供了各项具体功能方法,利用Parcel、IBinder和远程ServiceManager通信并返回结果(对应于工具生成的IxxService.Stub.Proxy)。

    获取本地代理,首先需要得到一个IBinder接口实例,这里主要是通过BinderInternal.getContextObject()完成的,属于系统级的一个特殊处理。实际上是native层创建的。远程ServiceManager,也就是addService等功能具体的实现,最终是service_manager.c中完成。

    这里可以看出,Binder通信的灵活性,不一定需要aidl文件,远端服务也不一定要包含一个Stub对象或者派生于Stub类,可以直接在native层。

    AIDL机制既可以实现跨进程通信,也支持在同一进程内的调用;在同一进程时,onServiceConnected回调的入参Binder对象,就是服务端返回的Binder实例,无需转换(对于进程的判断,以及Binder对象的对应区分,例如是Binder还是BinderProxy,是在驱动里面判断的,详见binder.c中的binder_translate_handle)。

    2、Binder和Parcelable接口
    Binder进程通信机制帮我们解决的最大问题,就是能够通过一个代理来访问其他进程中的实例对象及其方法,其中的数据传输,大量使用了Parcel以及Parcelable接口。

    如果是跨进程传输自定义数据类(可序列化的),可以使用实现了Parcelable接口的自定义数据类,同样需要对应的aidl文件。如果一个类在创建实例时,必须调用无法序列化的组件,则需要给客户端提供代理才能访问该类,也就是说,服务端的实现必须派生于Ixxx.Stub(Binder的派生类),使得客户端通过某种方式可以获取其代理。

    对于功能简单的调用,例如数据访问相关功能,使用一个实现了Parcelable接口的类基本就可以了,最多是引用其他aidl接口。例如KeyEvent,用于序列化的构造函数KeyEvent(Parcel in)里面都是可以可以序列化的数据类型。但如果自定义类的功能复杂,依赖大量组件,重点是构造函数参数涉及到不属于aidl可以序列化的类时,则无法实现Parcelable接口,只能给调用者/客户端提供一个代理来访问这些功能,这时候就需要定义aidl,并且让功能实现类派生于Stub(实质上是派生于Binder类)。例如Session类,其构造函数的几个参数都不能序列化,这个是其没有实现Parcelable接口却却实现了IWindowSession.Stub的关键原因。

    (相关完整且成体系的文章,可参见本人原创的开源电子书《Android系统与性能优化》,地址:https://github.com/carylake/androidnotes)

    展开全文
  • Binder 是什么?...3.共享内存 高效 安全性差 4.管道 需要2次拷贝 5.binder特殊管道 1.速度快一次拷贝,2.安全 Binder怎么实现一次拷贝,保证安全性 在Android中init 会启动ServiceManager来查询注册Binder。 Bi
  • 4.4.4 JVM内存为什么分成新生代,老年代,持久代。新生代中为什么分为Eden和Survivor。 4.4.5 JVM中一完整的GC流程是怎样的,对象如何晋升到老年代,说说你知道的种主要的JVM参数。 4.4.6 你知道哪种...
  • visual source safe 教程

    2010-07-14 11:03:58
    3) 在file to share列表中选择要共享的文件,如果你的文件没有显示,在项目列表中 3.3.9删除/恢复文件或文件夹 如果想从VSS中移走某个文件,你必须首先确定是仅仅从项目中移走,还是从VSS数据库中移走。你还...
  • 3) 在file to share列表中选择要共享的文件,如果你的文件没有显示,在项目列表中 3.3.9删除/恢复文件或文件夹 如果想从VSS中移走某个文件,你必须首先确定是仅仅从项目中移走,还是从VSS数据库中移走。你还...
  • 这个问题给我们教训的是:在直接对内存地址进行操作时,一定保证其值的合法性,否则容易引起内存操作越界,给系统的稳定性带来潜在的威胁。 【案例1.2.4】 近日在CDB并行测试中发现一个问题:我们需要的小区...
  • 我们想得到的结果是10循环a[i]保存着一个闭包,然后alert出从0到10,但是结果很出人意料,全部是10,为什么?哪里理解的不对呢?a[i]明明是内部函数,然后让它访问另外...
  • 进程间通信的方式有 共享内存, 管道 ,Socket ,消息队列 , DDE等 18.C++中什么数据分配在栈或堆中,New分配数据是在近堆还是远堆中? 答:栈: 存放局部变量,函数调用参数,函数返回值,函数返回地址。由系统管理...
  • 二十三种设计模式【PDF版】

    热门讨论 2011-05-30 14:13:49
    一个设计在最终完成之前常被复用好几次,而且每一次都有所修改。 有经验的面向对象设计者的确能做出良好的设计,而新手则面对众多选择无从下手,总是求助于以前使用过的非面向对象 技术。新手需要花费较长时间...
  • RamDisk Plus,绝对好使

    2008-12-04 13:52:08
    次要载入十二十张的图片来作编排。AVI等必须一边解压缩一边播放的程式。压缩过的漫画图档,需一边看一边解压缩载入的。从光碟片里面看的资料影片,放置这加速又不会产生硬碟的破碎空间。依照个人的电脑使用...
  • 等数据全部恢复到另外一个盘或者硬盘后,打开文件仔细检查,确定都恢复对了,才能往源盘里面拷回去的,不能恢复一部分就拷回一部分,往源盘拷数据会影响下一的数据恢复。 如果没有另外一块足够大的盘来存数据...
  • 一个进程池的服务器程序 ... 流程大概如下: 1,父进程listen,创建pipe(下面所有父子进程之间的通信都用该pipe) 2,父进程预fork n个子进程 3,各个子进程accept(listenfd),即所有子进程竞争accept请求。...
  • Squid 中文权威指南

    2011-08-19 13:38:16
    假如你觉得squid 有用,请考虑以下面一种或种方法来回报该项目: 1.参与squid 用户讨论列表,回答问题和帮助新用户。 2.测试新版本,报告bug 或其他问题。 3.致力于在线文档和FAQ。假如你发现错误,将它报告给维护...
  • 在删除数据方面,由于都是Sqlite数据库,所以删除只是删数据,并不会减小磁盘内存,如果缩小db大小,可以自行设计方案; 注:①测试使用小米9手机,单表数据量从最小100条到最大200W条,字段为30个String+一个...
  • 在菜单上选择控制的用户, 并修改下面两项: Soft FILE size [aaa] Hard FILE size [aaa] 则修改后用户的文件大小最大为aaa×512 bytes. >如何验证? 可以用该用户登录系统, 使用命令“ulimit -f”和“ulimit -...
  • 英特尔面试专项准备

    2020-12-09 13:46:46
    如何查找已经在内存共享库?ldd命令的作用是什么? </li><li> <p>11、mmap系统调用讨论 </li></ul> 系统调用的返回值是什么?映射在用户空间的虚拟地址。 <p>mmap的实现过程能简单说说吗?...
  • 入门学习Linux常用必会60个命令实例详解doc/txt

    千次下载 热门讨论 2011-06-09 00:08:45
    建议在/mnt里建个/mnt/cdrom、/mnt/floppy、/mnt/mo等目录,当作目录的专用挂载点。举例而言,如挂载下列5个设备,其执行指令可能如下 (假设都是Linux的ext2系统,如果是Windows XX请将ext2改成vfat): 软盘 ==...
  • Java堆内存是线程共享的!面试官:你确定吗? 线上服务的FGC问题排查,看这篇就够了! 记一大促期间JVM堆外内存泄漏故障排查记录 性能调优、线上问题排查 类加载机制详解 垃圾回收机制 垃圾回收器、垃圾回收算法 ...
  • windows编程资料大全

    2008-10-26 13:55:44
    这个程序中有一个细节使用了一些技巧:通常,建立一个动态链接库时,链接器将静态数据标记为非共享,也就是说,每一个调用DLL的进程都获得自己的数据拷贝------在本程序中是g_hHookKbd、g_hHookMouse和g_...
  •  将QQ安装目录下的unins000.exe文件拷贝卸载文件的安装目录,再执行该程序即可!这种办法对于卸载那些反安装程序丢失或者损坏的文件有特效。 2、Winamp的卸载程序可以安全卸载大部分应用程序  首先在“我的...
  • 2.1.2 共享的内核空间 17 2.1.3 无处不在的内核模块 18 2.2 数据类型 19 2.2.1 基本数据类型 19 2.2.2 返回状态 19 2.2.3 字符串 20 2.3 重要的数据结构 21 2.3.1 驱动对象 21 2.3.2 设备对象 22 2.3.3 ...
  • 2.1.2 共享的内核空间 17 2.1.3 无处不在的内核模块 18 2.2 数据类型 19 2.2.1 基本数据类型 19 2.2.2 返回状态 19 2.2.3 字符串 20 2.3 重要的数据结构 21 2.3.1 驱动对象 21 2.3.2 设备对象 22 2.3.3 ...
  • 会计理论考试题

    2012-03-07 21:04:40
    A、可以减少屏幕损耗 B、可以节省计算机内存 C、可以保障系统安全 D、可以增加动感 36.记录在存储介质上的一组相关信息的集合称为 __D_ 。 A、程序 B、磁盘 C、软件 D、文件 37.在资源管理器中,双击扩展名为“.TXT...
  • 只能有一个窗口接受用户的输入。用户可以使用鼠标、键盘或其他输人设备与该窗口及拥有该窗口的应用程序进行交互。使用窗口函数可以创建和管理窗口。 窗口类函数(Window Class) 一个窗口类是一个属性的集合,...
  • vc++ 应用源码包_6

    热门讨论 2012-09-15 14:59:46
    大家都知道,现在流行的检测硬件软件视乎很神秘,我们获得各种信息好像比较难.但大多数这种软件或多或少的使用了WMI,如果我们能熟练掌握相信你也做的处理.另外WMI除了查询还能修改,比如3389端口,账号,密码,服务启动...

空空如也

空空如也

1 2 3
收藏数 54
精华内容 21
关键字:

内存共享要拷贝几次