(问)多线程下单例模式下全局变量共享问题
(面)多线程调用单例类中的方法会不会造成线程安全问题?
答案:不会。
局部变量不会受多线程影响;但成员变量会受到多线程影响。
多个线程应该是调用的同一个对象的同一个方法;
如果方法里无成员变量,那么不受任何影响;
如果方法里有成员变量,只有读操作,不受影响;存在写操作,考虑多线程影响值
.
当多个线程同时访问同一个方法的时候,jvm会给每个线程分配单独的局域变量,这样就不会出现问题了。
一 Java多线程
Java中的多线程 https://www.cnblogs.com/wxd0108/p/5479442.html
线程的生命周期
线程通常都有五种状态,创建、就绪、运行、阻塞和死亡
Thread 和 Runnable的区别
实例化线程对象有所不同:
extends Thread :t.start();
implements Runnable :new Thread(t).start();
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制(不能访问父类的私有成员?)
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
run()和start()方法的区别
run方法:是线程的任务处理逻辑的入口方法,它由Java虚拟机在运行相应线程时直接调用,而不是由应用代码进行调用。
调用run方法其实就是当作普通的方法的方式调用。并没有创建一个线程,程序中依旧只有一个主线程,必须等到run()方法里面的代码执行完毕,才会继续执行下面的代码,这样就没有达到加入线程的目的。
start方法:是启动相应的线程。启动一个线程实际是请求Java虚拟机运行相应的线程,而这个线程何时能够运行是由线程调度器决定的。start()调用并不表示相应线程已经开始运行,这个线程可能稍后运行。
创建并启动一个线程,真正实现了多线程。无需等待run()方法中的代码执行完毕,就可以接着执行下面的代码。此时start()的这个线程处于就绪状态,当得到CPU的时间片后就会执行其中的run()方法。这个run()方法包含了要执行的这个线程的内容,run()方法运行结束线程终止。
start()方法能够异步的调用run()方法,但是直接调用run()方法却是同步的,无法达到多线程的目的。因此,只用通过调用线程类的start()方法才能达到多线程的目的。
双重校验锁的单例模式
volatile修饰singleton很有必要,voliatile防止了指令重排
在这里插入代码片
volatile关键字
在现在的java模型下,线程可以把变量保存在本地内存(比如寄存器)中,而不是直接在主内存中进行读写,这就可能造成一个线程在主内存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量的拷贝,造成数据不一致。
sychronized关键字
sychronized和volatile的区别
二 线程池
ThreadPoolExecutor
线程池的作用
在实践应用中创建线程池主要是为了:
- 减少资源开销:减少每次创建、销毁线程的开销;
- 提高响应速度:请求到来时,线程已创建好,可直接执行,提高响应速度;
- 提高线程的可管理性:线程是稀缺资源,需根据情况加以限制,确保系统稳定运行;
通过 Callable 和 Future 创建线程
1.创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。
2.创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。
3.使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。
4.调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。
实现Runnable和Callable接口的区别
https://www.jianshu.com/p/27b7340d8470
完
参考资料
Java中的多线程
https://www.cnblogs.com/wxd0108/p/5479442.html
volatile的设计原理
https://mp.weixin.qq.com/s/WTqdSz-lc5zzelJgk4Co8g
ThreadPoolExecutor
https://mp.weixin.qq.com/s/ROQMBFw0DWM4sSP-sdy-IA