Java语言面试-Java多线程面试

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yaoming168/article/details/88952158

(四) 线程、多线程和线程池
三、服务器只提供数据接收接口,在多线程或多进程条件下,如何保证数据的有序到达?
第一部分多线程
二、Java有哪些线程池?他们的区别是什么?线程池工作流程是怎样的?线程池实现原理是怎样的?Cache线程池有哪些弊端?
三、多线程间的通信方式?
四、synchronize关键字怎么用的?还知道哪些同步的方式?
五、Thread直接调用run方法会怎么样?start方法作用是什么?
六、volatile关键字的作用是什么?
七、怎么安全停止一个线程任务?原理是什么?线程池里有类似机制吗?
八、线程同步的问题,常用的线程同步
九、Asynctask和线程池,GC相关(怎么判断哪些内存该GC,GC算法)
1、AsyncTask的工作原理
AsyncTask是Android本身提供的一种轻量级的异步任务类。它可以在线程池中执行后台任务,然后把执行的进度和最终的结果传递给主线程更新UI。实际上,AsyncTask内部是封装了Thread和Handler。虽然AsyncTask很方便的执行后台任务,以及在主线程上更新UI,但是,AsyncTask并不合适进行特别耗时的后台操作,对于特别耗时的任务,个人还是建议使用线程池。
AsyncTask提供有4个核心方法:
1、onPreExecute():该方法在主线程中执行,在执行异步任务之前会被调用,一般用于一些准备工作。
2、doInBackground(String… params):这个方法是在线程池中执行,此方法用于执行异步任务。在这个方法中可以通过publishProgress方法来更新任务的进度,publishProgress方法会调用onProgressUpdate方法,另外,任务的结果返回给onPostExecute方法。
3、onProgressUpdate(Object… values):该方法在主线程中执行,主要用于任务进度更新的时候,该方法会被调用。
4、onPostExecute(Long aLong):在主线程中执行,在异步任务执行完毕之后,该方法会被调用,该方法的参数及为后台的返回结果。
除了这几个方法之外还有一些不太常用的方法,如onCancelled(),在异步任务取消的情况下,该方法会被调用。
源码可以知道从上面的execute方法内部调用的是executeOnExecutor()方法,即executeOnExecutor(sDefaultExecutor, params);而sDefaultExecutor实际上是一个串行的线程池。而onPreExecute()方法在这里就会被调用了。接着看这个线程池。AsyncTask的执行是排队执行的,因为有关键字synchronized,而AsyncTask的Params参数就封装成为FutureTask类,FutureTask这个类是一个并发类,在这里它充当了Runnable的作用。接着FutureTask会交给SerialExecutor的execute方法去处理,而SerialExecutor的executor方法首先就会将FutureTask添加到mTasks队列中,如果这个时候没有任务,就会调用scheduleNext()方法,执行下一个任务。如果有任务的话,则执行完毕后最后在调用 scheduleNext();执行下一个任务。直到所有任务被执行完毕。而AsyncTask的构造方法中有一个call()方法,而这个方法由于会被FutureTask的run方法执行。所以最终这个call方法会在线程池中执行。而doInBackground这个方法就是在这里被调用的。我们好好研究一下这个call()方法。mTaskInvoked.set(true);表示当前任务已经执行过了。接着执行doInBackground方法,最后将结果通过postResult(result);方法进行传递。postResult()方法中通过sHandler来发送消息,sHandler的中通过消息的类型来判断一个MESSAGE_POST_RESULT,这种情况就是调用onPostExecute(result)方法或者是onCancelled(result)。另一种消息类型是MESSAGE_POST_PROGRESS则调用更新进度onProgressUpdate。
三、有三个线程T1,T2,T3,怎么确保它们按顺序执行?
在多线程中有多种方法让线程按特定顺序执行,你可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行。为了确保三个线程的顺序你应该先启动最后一个(T3调用T2,T2调用T1),这样T1就会先完成而T3最后完成。
线程间通信
我们知道线程是CPU调度的最小单位。在Android中主线程是不能够做耗时操作的,子线程是不能够更新UI的。而线程间通信的方式有很多,比如广播,Eventbus,接口回掉,在Android中主要是使用handler。handler通过调用sendmessage方法,将保存消息的Message发送到Messagequeue中,而looper对象不断的调用loop方法,从messageueue中取出message,交给handler处理,从而完成线程间通信。
线程池
Android中常见的线程池有四种,FixedThreadPool、CachedThreadPool、ScheduledThreadPool、SingleThreadExecutor。
FixedThreadPool线程池是通过Executors的new FixedThreadPool方法来创建。它的特点是该线程池中的线程数量是固定的。即使线程处于闲置的状态,它们也不会被回收,除非线程池被关闭。当所有的线程都处于活跃状态的时候,新任务就处于队列中等待线程来处理。注意,FixedThreadPool只有核心线程,没有非核心线程。
CachedThreadPool线程池是通过Executors的newCachedThreadPool进行创建的。它是一种线程数目不固定的线程池,它没有核心线程,只有非核心线程,当线程池中的线程都处于活跃状态,就会创建新的线程来处理新的任务。否则就会利用闲置的线程来处理新的任务。线程池中的线程都有超时机制,这个超时机制时长是60s,超过这个时间,闲置的线程就会被回收。这种线程池适合处理大量并且耗时较少的任务。这里得说一下,CachedThreadPool的任务队列,基本都是空的。
ScheduledThreadPool线程池是通过Executors的newScheduledThreadPool进行创建的,它的核心线程是固定的,但是非核心线程数是不固定的,并且当非核心线程一处于空闲状态,就立即被回收。这种线程适合执行定时任务和具有固定周期的重复任务。
SingleThreadExecutor线程池是通过Executors的newSingleThreadExecutor方法来创建的,这类线程池中只有一个核心线程,也没有非核心线程,这就确保了所有任务能够在同一个线程并且按照顺序来执行,这样就不需要考虑线程同步的问题。

二十四、进程和线程的区别
进程是cpu资源分配的最小单位,线程是cpu调度的最小单位。
进程之间不能共享资源,而线程共享所在进程的地址空间和其它资源。
一个进程内可拥有多个线程,进程可开启进程,也可开启线程。
一个线程只能属于一个进程,线程可直接使用同进程的资源,线程依赖于进程而存在。
二十五. 实现多线程的两种方法:Thread与Runable。
二十六. 线程同步的方法:synchronized、lock、reentrantLock等。
二十七. 锁的等级:方法锁、对象锁、类锁。
二十八. 写出生产者消费者模式。
三十八. ThreadLocal的设计理念与作用。
. ThreadPool用法与优势。
在多线程环境中使用Thread Pool,可以提高运行效率,不用每次新建一个线程,循环利用线程。
三十九. Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。

四十. wait()和sleep()的区别。
1). sleep()不释放同步锁,wait()释放同步锁.
2). sleep是Thread类的方法,wait是Object的方法。wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用

一、开启线程的三种方式?
答:https://www.cnblogs.com/3s540/p/7172146.html
二、进程和线程的区别?什么时候用进程?什么时候用线程?
答:首先得知道什么是进程什么是线程?
我的理解是进程是指在系统中正在运行的一个应用程序;程序一旦运行就是进程,或者更专业化来说:进程是指程序执行时的一个实例。
线程是进程的一个实体。
进程——资源分配的最小单位,线程——程序执行的最小单位。
线程进程的区别体现在几个方面:
第一:因为进程拥有独立的堆栈空间和数据段,所以每当启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这对于多进程来说十分“奢侈”,系统开销比较大,而线程不一样,线程拥有独立的堆栈空间,但是共享数据段,它们彼此之间使用相同的地址空间,共享大部分数据,比进程更节俭,开销比较小,切换速度也比进程快,效率高,但是正由于进程之间独立的特点,使得进程安全性比较高,也因为进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。一个线程死掉就等于整个进程死掉。
第二:体现在通信机制上面,正因为进程之间互不干扰,相互独立,进程的通信机制相对很复杂,譬如管道,信号,消息队列,共享内存,套接字等通信机制,而线程由于共享数据段所以通信机制很方便。。
3.属于同一个进程的所有线程共享该进程的所有资源,包括文件描述符。而不同过的进程相互独立。
4.线程又称为轻量级进程,进程有进程控制块,线程有线程控制块;
5.线程必定也只能属于一个进程,而进程可以拥有多个线程而且至少拥有一个线程;
第四:体现在程序结构上,举一个简明易懂的列子:当我们使用进程的时候,我们不自主的使用if else嵌套来判断pid,使得程序结构繁琐,但是当我们使用线程的时候,基本上可以甩掉它,当然程序内部执行功能单元需要使用的时候还是要使用,所以线程对程序结构的改善有很大帮助。
进程与线程的选择取决以下几点:
1、需要频繁创建销毁的优先使用线程;因为对进程来说创建和销毁一个进程代价是很大的。
2、线程的切换速度快,所以在需要大量计算,切换频繁时用线程,还有耗时的操作使用线程可提高应用程序的响应
3、因为对CPU系统的效率使用上线程更占优,所以可能要发展到多机分布的用进程,多核分布用线程;
4、并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求;
5、需要更稳定安全时,适合选择进程;需要速度时,选择线程更好。
三、为什么要有线程,而不是仅仅用进程?
一)进程是什么?
程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程。程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念。
在多道编程中,我们允许多个程序同时加载到内存中,在操作系统的调度下,可以实现并发地执行。这是这样的设计,大大提高了CPU的利用率。进程的出现让每个用户感觉到自己独享CPU,因此,进程就是为了在CPU上实现多道编程而提出的。

二)有了进程为什么还要线程?
1、进程缺点:
进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。
进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行。
2、线程的优点:
因为要并发,我们发明了进程,又进一步发明了线程。只不过进程和线程的并发层次不同:进程属于在处理器这一层上提供的抽象;线程则属于在进程这个层次上再提供了一层并发的抽象。如果我们进入计算机体系结构里,就会发现,流水线提供的也是一种并发,不过是指令级的并发。这样,流水线、线程、进程就从低到高在三个层次上提供我们所迫切需要的并发!
3、除了提高进程的并发度,线程还有个好处,就是可以有效地利用多处理器和多核计算机。现在的处理器有个趋势就是朝着多核方向发展,在没有线程之前,多核并不能让一个进程的执行速度提高,原因还是上面所有的两点限制。但如果讲一个进程分解为若干个线程,则可以让不同的线程运行在不同的核上,从而提高了进程的执行速度。
四、run()和start()方法区别
start():该方法是在当前线程中启动一个新的线程,而新启动的线程会调用run()方法,同时该方法不能重复调用;
run() :该方法和普通的方法一样,可以重复执行,不会创建新的线程。
五、如何控制某个方法允许并发访问线程的个数?
答案:使用Semaphore控制某个方法允许并发访问的线程的个数,Semaphore两个重要的方法就是
semaphore.acquire() 请求一个信号量,这时候的信号量个数-1(一旦没有可使用的信号量,也即信号量个数变为负数时,再次请求的时候就会阻塞,直到其他线程释放了信号量);
semaphore.release() 释放一个信号量,此时信号量个数+1;
参考答案:
1、https://blog.csdn.net/manzhizhen/article/details/81413014
2、https://blog.csdn.net/anhenzhufeng/article/details/70225415

六、在Java中wait和seelp方法的不同
答:对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。
在调用sleep()方法的过程中,线程不会释放对象锁。
而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。
参考答案:
1、https://blog.csdn.net/cwl_0514/article/details/79894108
2、https://www.cnblogs.com/loren-Yang/p/7538482.html
七、谈谈wait/notify关键字的理解
等待对象的同步锁,需要获得该对象的同步锁才可以调用这个方法,否则编译可以通过,但运行时会收到一个异常:IllegalMonitorStateException。

调用任意对象的 wait() 方法导致该线程阻塞,该线程不可继续执行,并且该对象上的锁被释放。

唤醒在等待该对象同步锁的线程(只唤醒一个,如果有多个在等待),注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。

调用任意对象的notify()方法则导致因调用该对象的 wait()方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。

八、什么导致线程阻塞?线程如何关闭?
阻塞式方法是指程序会一直等待该方法完成期间不做其他事情,ServerSocket的accept()方法就是一直等待客户端连接。这里的阻塞是指调用结果返回之前,当前线程会被挂起,直到得到结果之后才会返回。此外,还有异步和非阻塞式方法在任务完成前就返回。

一种是调用它里面的stop()方法

另一种就是你自己设置一个停止线程的标记 (推荐这种)

十、讲一下java中的同步的方法
参考答案:https://www.cnblogs.com/duanxz/p/3709608.html?utm_source=tuicool&utm_medium=referral
十一、数据一致性如何保证?
参考答案:https://www.cnblogs.com/jiumao/p/7136631.html
十二、如何保证线程安全?
1.synchronized;
2.Object方法中的wait,notify;
3.ThreadLocal机制 来实现的。
十三、如何实现线程同步?
1、synchronized关键字修改的方法。2、synchronized关键字修饰的语句块3、使用特殊域变量(volatile)实现线程同步
十四、两个进程同时要求写或者读,能不能实现?如何防止进程的同步?
答:
允许多个读者同时执行读操作;
不允许读者、写者同时操作;
不允许多个写者同时操作。

java.util.concurrent.locks.ReadWriteLock;
java.util.concurrent.locks.ReentrantReadWriteLock;
控制访的数量即可。Java并发库的Semaphore可以完成信号量的控制,Semaphore可以控制某个资源可被同时访问的数量,通过acquire()获取一个许可,如果没有就等待,而release()释放一个许可。

十五、线程间操作List
List list = Collections.synchronizedList(new ArrayList());
使用Collections.synchronizedList()构建List;2操作list的方法使用同步锁。
为何会两者都用,因为Collections.synchronizedList()构建的list只针对list的add(obj)、poll(obj)等方法做同步,在多线程中直接使用方法会同步,但是在操作list时,add(obj)、poll(obj)方法之前不能保证obj是否被其他线程操作过。
十六、Java中对象的生命周期

  1. 创建阶段(Created)
    为对象分配存储空间
    开始构造对象
    从父类到子类对static成员进行初始化
    父类成员变量按照顺序初始化,递归调用父类的构造方法
    子类成员变量按照顺序初始化,子类构造方法调用
    一旦对象被创建,并有某个引用指向它,这个对象的状态就切换到了应用阶段(In Use)

  2. 应用阶段(In Use)
    对象至少被一个强引用持有并且对象在作用域内

  3. 不可见阶段(Invisible)
    程序本身不再持有该对象的任何强引用,但是这些引用可能还存在着;
    一般具体是指程序的执行已经超过该对象的作用域了

  4. 不可达阶段(Unreachable)
    该对象不再被任何强引用所持有;
    可能仍被JVM等系统下的某些已经装载的惊天变灵或者线程或JNI所持有,这些特殊的强引用被称为GC root,这种情况容易导致内存泄露,无法被回收

  5. 收集阶段(Collected)
    对象不可达,并且GC已经准备好对该对象占用的内存空间重新分配的时候,处于手机阶段。
    如果重写了finazlie()方法,则会去执行该方法。
    尽量不要重写finazlie()方法,因为有可能影响JVM的对象分配与回收速度或者可能造成该对象的再次复活

  6. 终结阶段
    当对象执行完finalize()方法之后,仍然处于不可达状态时,则该对象进入终结阶段。在这个阶段,内存空间等待GC进行回收

  7. 对象空间的重新分配
    GC对该对象占有的内存空间进行回收或者再分配,该对象彻底消失

十七、Synchronized用法和原理
参考答案:https://www.cnblogs.com/paddix/p/5367116.html

十九、谈谈对Synchronized关键字,类锁,方法锁,重入锁的理解
java的对象锁和类锁:java的对象锁和类锁在锁的概念上基本上和内置锁是一致的,但是,两个锁实际是有很大的区别的,对象锁是用于对象实例方法,或者一个对象实例上的,类锁是用于类的静态方法或者一个类的class对象上的。我们知道,类的对象实例可以有很多个,但是每个类只有一个class对象,所以不同对象实例的对象锁是互不干扰的,但是每个类只有一个类锁。但是有一点必须注意的是,其实类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的
二十、static synchronized 方法的多线程访问和作用
二十一、同一个类里面两个synchronized方法,两个线程同时访问的问题
二十二、volatile的原理
二十三、谈谈volatile关键字的用法和作用
二十五、谈谈NIO的理解
二十六、synchronized 和volatile 关键字的区别
1.volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
2.volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
3.volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
4.volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
5.volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

二十七、synchronized与Lock的区别
二十八、ReentrantLock 、synchronized和volatile比较
二十九、ReentrantLock的内部实现
三十、lock原理
三十一、死锁的四个必要条件?
三十二、怎么避免死锁?
三十三、对象锁和类锁是否会互相影响?
三十四、什么是线程池,如何使用?
三十五、Java的并发、多线程、线程模型
三十六、谈谈对多线程的理解
三十七、多线程有什么要注意的问题?
三十八、谈谈你对并发编程的理解并举例说明
答:
对于并发编程, 涉及的技术点非常多, 我们首先需要明确一些基本概念,只有概念清晰,才能做到在以后深入学习关键技术的过程中不致于感觉到吃力和迷惑。 其次,我们还需要明白在并发编程最需要关注的问题是什么? 带着关键问题去学习,才能够起到事办功倍、稳扎稳打的效果。
下面是我所总结的一些很多人容易混淆的概念:

  1. 高并发、多线程
    高并发
    高并发是请求,指的是多个客户端同一时刻向服务端发送请求, 它是一种现象。
    比如,电商网站在双11凌晨12:00分 同时有2000个下单请求。
    多线程
    多线程是处理,指的是同一时刻多个执行者处理同一类的任务, 它有具体的实现。比如
    电商网站在双11凌晨12:00分同时有100个线程处理2000个下单请求。
  2. 并行、并发
    并行
    多核cpu的情况, 多个任务执行者并行处理任务
    并发
    单个cpu的情况下,cpu间断性的执行多个任务。
    举个打扫房间的例子,如果你有1把扫帚需要打扫2个房间, A房间打扫到一半的时候,你再切换到B房间,这就现象称之为并发; 如果你有2把扫帚,这个时候就可以同时打扫2个房间了,这种现象称之为并行。
  3. 多线程就一定效率高吗?
    从上面打扫房间的例子可以看出, 多线程并非效率一定高。 只有在并行的情况下效率才能保证, 并发需要做上下文切换,会影响整体性能。
  4. 并发编程需要注意的2个问题
    并发编程尤其需要注意的是共享数据的安全性和锁性能方面的问题, 在并发编程领域的讨论中,几乎90%以上都是围绕这2大主题展开,甚至jdk每个版本的升级都有针对这2方面问题做优化, 如jdk5之后的各种锁优化技术、volatile、threadlocal关键字等。
    共享数据的安全性问题
    堆内存和方法区内存可以共享。 因此成员变量和静态变量存在数据安全性问题。
    锁竟争带来的程序效率问题
    多个线程访问共享资源时,只有获取到锁的线程才允许访问共享资源,未获得到锁的线程只能在临界区进行排队等待,试想如果有1000个线程同时访问共享资源,那么最后一个线程必须要等前面999个线程执行完后才能够进入监界区操作共享资源。
    如果锁没有控制好,非常容易出现程序整体性能低下的情况。

三十九、谈谈你对多线程同步机制的理解?
答:线程同步是为了确保线程安全,所谓线程安全指的是多个线程对同一资源进行访问时,有可能产生数据不一致问题,导致线程访问的资源并不是安全的。如果多线程程序运行结果和单线程运行的结果是一样的,且相关变量的值与预期值一样,则是线程安全的。
Java中与线程同步有关的关键字/类包括:
volatile、synchronized、Lock、AtomicInteger等concurrent包下的原子类。。。等
接下来讨论这几种同步方法。
volatile
volatile一般用在多个线程访问同一个变量时,对该变量进行唯一性约束,volatile保证了变量的可见性,不能保证原子性。
用法(例):private volatile booleanflag = false
保证变量的可见性:volatile本质是告诉JVM当前变量在线程寄存器(工作内存)中的值是不确定的,需要从主存中读取,每个线程对该变量的修改是可见的,当有线程修改该变量时,会立即同步到主存中,其他线程读取的是修改后的最新值。
不能保证原子性:原子性指的是不会被线程调度机制打断的操作,在java中,对基本数据类型的变量的读取和赋值操作是原子性操作。自增/自减操作不是原子性操作。例如:i++,其实是分成三步来操作的:1)从主存中读取i的值;2)执行+1操作;3)回写i的值。volatile关键字并不能保证原子性操作。非原子操作都会产生线程安全的问题,那么如何实现自增/自减的原子性呢?后续将有讲解。
synchronized
synchronized提供了一种独占的加锁方式,是比较常用的线程同步的关键字,一般在“线程安全的单例”中普遍使用。该关键字能够保证代码块的同步性和方法层面的同步。
用法(例):1)代码块同步
//使用synchronized关键字实现线程安全的单例模式
private static Singleton instance;
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class)
{
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
privateSingleton(){ }

2)方法同步
public static synchronized Singleton getInstance2(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
private Singleton(){ }
很多人说synchronized在性能上存在较大问题,但并没有真实环境产生的数据比较说明,因此在这里不好讨论性能问题。
volatile和synchronized的区别
1) volatile通过变量的可见性,指定线程必须从主存中读取变量的最新值;synchronized通过阻塞线程的方式,只有当前线程能访问该变量,锁定了当前变量。
2) volatile使用在变量级别;synchronized可以使用在变量、方法、类级别
3) volatile不会造成线程阻塞;synchronized可能会造成线程阻塞
4) volatile不能保证原子性;synchronized能保证原子性
5) volatile标记的变量不会被编译器优化;synchronized标记的变量有可能会被编译器优化(指令重排)。

如何保证自增/自减的原子性
1) 使用java.util.concurrent包下提供的原子类,如AtomicInteger、AtomicLong、AtomicReference等。
用法:
AtomicInteger atomicInteger = new AtomicInteger();
atomicInteger.getAndIncrement();//实现原子自增
atomicInteger.getAndDecrement();//实现原子自减

2)使用synchronized同步代码块
Synchronized(this){
value++;
}
3)使用Lock显示锁同步代码块
private Lock lock = new ReentrantLock();
private final int incrementAndGet(){
lock.lock();
try
{
return value++;
}
finally
{
// TODO: handle finally clause
lock.unlock();
}
}

四十、如何保证多线程读写文件的安全?
答:对于读写操作,一般都比较耗时耗性能,为了保持其安全性,我们一般要采取“多读单写”模式:
(1)同一时间,只能有1个线程进行写的操作
(2)同一时间,允许有多个线程进行读的操作
(3)同一时间,不允许既有写的操作,又有读的操作
四十一、多线程断点续传原理
多线程下载涉及到的知识点:
1、Service的使用:我们在Service中去下载文件;
2、Thread的使用:Service本身不支持耗时操作,所以我们要去开启线程;
3、Sqlite的使用:使用数据库来存储每个线程下载的文件的进度,和文件的下载情况;
4、权限:涉及到文件的读写就要用到权限;
5、BroadCastReceiver的使用:通过广播来更新下载进度;
6、线程池使用:使用线程池来管理线程,减少资源的浪费
7、HttpUrlConnection的使用:下载文件使用的
8、ListView和BaseAdapter的使用:下载列表的显示
9、RandomAccessFile使用
参考答案:https://blog.csdn.net/hello_1s/article/details/81391377
四十二、断点续传的实现
答:
参考答案:https://blog.csdn.net/u012319157/article/details/79111491
(五)并发编程有关知识点

第一、Java 内存模型
java线程安全总结
注:https://www.iteye.com/topic/806990
深入理解java内存模型系列文章
注:http://ifeve.com/java-memory-model-0/
第二、线程状态:
一张图让你看懂JAVA线程间的状态转换
注:https://my.oschina.net/mingdongcheng/blog/139263
第三、锁:
锁机制:synchronized、Lock、Condition
注:https://blog.csdn.net/ymrfzr/article/details/51427162
Java 中的锁
注:http://wiki.jikexueyuan.com/project/java-concurrent/locks-in-java.html
第四、并发编程:
Java并发编程:Thread类的使用
注:http://www.cnblogs.com/dolphin0520/p/3920357.html
Java多线程编程总结
注:https://blog.51cto.com/lavasoft/27069
Java并发编程的总结与思考
注:https://www.jianshu.com/p/053943a425c3#
Java并发编程实战-----synchronized
注:http://www.cnblogs.com/chenssy/p/4701027.html
深入分析ConcurrentHashMap
注:https://infoq.cn/article/ConcurrentHashMap

猜你喜欢

转载自blog.csdn.net/yaoming168/article/details/88952158