凤岗金属制品东莞网站建设技术支持,广东网络优化推广,seo新人培训班,溧阳建设局网站Java并发编程
基础知识
1. 为什么要使用并发编程#xff1f; 提升多核系统的CPU利用率一般来说一台主机上的会有多个CPU核心#xff0c;我们可以创建多个线程#xff0c;理论 上讲操作系统可以将多个线程分配给不同的CPU去执行#xff0c;每个CPU执行一个线程#xff0c…Java并发编程
基础知识
1. 为什么要使用并发编程 提升多核系统的CPU利用率一般来说一台主机上的会有多个CPU核心我们可以创建多个线程理论 上讲操作系统可以将多个线程分配给不同的CPU去执行每个CPU执行一个线程这样就提高了 CPU的使用效率如果使用单线程就只能有一个CPU核心被使用。 比如当我们在网上购物时为了提升响应速度需要拆分减库存生成订单等等这些操作就可 以进行拆分利用多线程的技术完成。面对复杂业务模型并行程序会比串行程序更适应业务需求 而并发编程更能吻合这种业务拆分 。 简答提升cpu利用率方便业务拆分提升性能。
2. 多线程应用场景
例如 迅雷多线程下载、数据库连接池、分批发送短信等等。
3. 并发编程有什么缺点 并发编程并不是总能提升效率可能遇到一些问题如死锁、上下文切换、内存泄露、线程安全等等。 4. 并发编程的三个必要因素
原子性这个业务要么全部成功、要么全部失败。可见性一个线程对共享变量进行了修改其他线程是可见的。synchronized,volatile有序性程序执行的顺序按照代码执行的顺序执行。处理器可能会对指令进行重排序
5. Java 程序中怎么保证多线程的运行安全
出现线程安全问题的原因一般都是三个原因
线程切换带来的原子性问题 解决办法使用多线程之间同步synchronized或使用锁(lock)。缓存导致的可见性问题 解决办法synchronized、volatile、LOCK可以解决可见性问题。编译优化带来的有序性问题 解决办法Happens-Before 规则可以解决有序性问题。
6. 并行和并发有什么区别
并发多个任务在同一个 CPU 核上按细分的时间片轮流(交替)执行从逻辑上来看那些任务是 同时执行。并行单位时间内多个处理器或多核处理器同时处理多个任务是真正意义上的“同时进行”。串行有n个任务由一个线程按顺序执行。由于任务、方法都在一个线程执行所以不存在线程不 安全情况也就不存在临界区的问题。
7. 说一下 runnable 和 callable 有什么区别
相同点
都是接口都可以编写多线程程序都采用Thread.start()启动线程
主要区别
Runnable 接口 run 方法无返回值Callable 接口 call 方法有返回值是个泛型和Future、 FutureTask配合可以用来获取异步执行的结果Runnable 接口 run 方法只能抛出运行时异常且无法捕获处理Callable 接口 call 方法允许抛出 异常可以获取异常信息 注Callalbe接口支持返回执行结果需要调用FutureTask.get()得到 此方法会阻塞主进程的继续往下执行如果不调用不会阻塞。
8. 线程的run()和start()有什么区别
每个线程都是通过某个特定Thread对象所对应的方法run()来完成其操作的run()方法称为线程 体。通过调用Thread类的start()方法来启动一个线程。 start() 方法用于启动线程run() 方法用于执行线程的运行时代码。 run() 可以重复调用而 start()只能调用一次。start()方法来启动一个线程真正实现了多线程运行。调用start()方法无需等待run方法体代码执 行完毕可以直接继续执行其他的代码 此时线程是处于就绪状态并没有运行。 然后通过此 Thread类调用方法run()来完成其运行状态 run()方法运行结束 此线程终止。然后CPU再调度 其它线程。run()方法是在本线程里的只是线程里的一个函数而不是多线程的。 如果直接调用run()其实 就相当于是调用了一个普通函数而已直接待用run()方法必须等待run()方法执行完毕才能执行下 面的代码所以执行路径还是只有一条根本就没有线程的特征所以在多线程执行时要使用 start()方法而不是run()方法。
9. 为什么我们调用 start() 方法时会执行 run() 方法为什么我们不能直接调用run() 方法 总结 调用 start 方法方可启动线程并使线程进入就绪状态而 run 方法只是 thread 的一个普通方法 调用还是在主线程里执行。 10. 你是如何调用 wait() 方法的使用 if 块还是循环为什么
处于等待状态的线程可能会收到错误警报和伪唤醒如果不在循环中检查等待条件程序就会在没 有满足结束条件的情况下退出。wait() 方法应该在循环调用因为当线程获取到 CPU 开始执行的时候其他条件可能还没有满足 所以在处理前循环检测条件是否满足会更好。下面是一段标准的使用 wait 和 notify 方法的 代码
synchronized (monitor) { // 判断条件谓词是否得到满足
while(!locked) {// 等待唤醒monitor.wait();
}// 处理其他的业务逻辑
}11. 为什么 wait notify 和 notifyAll 必须在同步方法或者同步块中被调用
先来看看一个实际代码编写场景中不当使用wait方法导致异常的案例。 小A写的代码抛出了 java.lang.IllegalMonitorStateException 异常信息。
public class WaitDemo {public static void main(String[] args) throws Exception {Object o new Object();o.wait();//业务逻辑代码}
}小A通过查看源码确认了抛出 IllegalMonitorStateException 异常是由于调用wait方法的时当前线程没有获取到调用对象的锁。 Throws:IllegalMonitorStateException – if the current thread is not the owner of the object’s monitor. 根据错误原因将代码改成如下业务代码正常运行。
public class WaitDemo {public static void main(String[] args) throws Exception {Object o new Object();synchronized (o){o.wait();}//业务逻辑代码}
}通过这个异常的处理小A认识到自己对于wait和notify方法缺乏足够的了解导致了异常的发生下面我们一起来学习下wait和notify方法
wait和notify方法介绍
wait和notify是Object类中定义的方法。调用这两个方法的前提条件当前线程拥有调用者的锁。 wait方法有好几个重载方法但最终都调用了如下的wait本地方法。调用wait方法后当前线程会进入waiting状态直到其他线程调用此对象的notify、notifyAll方法或者指定的等待时间过去。
public final native void wait(long timeout) throws InterruptedException;notify和notifyAll方法,两者的区别是notify方法唤醒一个等待在调用对象上的线程notifyAll方法唤醒所有的等待在调用对象上的线程。 那么唤醒后的线程是否就可以直接执行了 答案是否定的。唤醒后的线程需要获取到调用对象的锁后才能继续执行。
public final native void notify();
public final native void notifyAll();