发布于2021-03-13 13:48 阅读(1730) 评论(0) 点赞(21) 收藏(2)
import java.util.concurrent.TimeUnit;
public class T01 {
// volatile使得线程可见
volatile boolean running =true;
void m(){
System.out.println("m start");
while (running){
}
System.out.println("m end");
}
public static void main(String[] args) {
T01 t = new T01();
new Thread(t::m,"t1").start();
try{
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
t.running = false;
}
}
这段代码使用volatile和不使用volatile有明显区别
使用volatile:
不使用volatile:
####测试new Thread启动一个线程。调用了m方法。睡了1秒后。如果普通变量没有被volatile修饰。
将把running值从内存读到t1线程工作区。运行过程中无须每次都去读堆内存。所以值被修改是感知不到。必须等while循环结束。
如果running值被volatile修饰。会强制所有线程去堆内存读取running值。则会被感知到false跳出循环
####volatile作用:
1、保证线程可见性。堆内存也就是共享内存。当我们的线程去访问这个值的时候。会将此值copy一份。不需要检查有没有新值。这也是线程的不可见性。
而volatile则会强制读取堆内存变化值。一个线程改变。另外线程也能看到。
2、禁止指令重新排序
并行执行cpu指令。提高效率
单例就是指jvm内存里永远只有某一个类的一个实例
不需要new很多对象
饿汉模式和懒汉模式
饿汉。就是进入这个类。就给你实例化一个对象
public class Mgr01 {
// 单例模式饿汉(先上来就new一个对象)
private static final Mgr01 INSTANCE = new Mgr01();
private Mgr01(){
}
public static Mgr01 getInstance(){
return INSTANCE;
}
public void m(){
System.out.println("m");
}
public static void main(String[] args) {
Mgr01 m1 = Mgr01.getInstance();
Mgr01 m2 = Mgr01.getInstance();
System.out.println(m1 == m2);
}
}
当我每次进来调用getInstance方法就初始化一次对象。其实这里需要判断INSTANCE是否为null再返回。是null的时候再返回,不要初始化多个对象
因此被我改写成这样。
import org.springframework.util.ObjectUtils;
public class Mgr01 {
// 单例模式饿汉(先上来就new一个对象)
private static final Mgr01 INSTANCE = new Mgr01();
private Mgr01(){
}
public static Mgr01 getInstance(){
if (ObjectUtils.isEmpty(INSTANCE)){
return INSTANCE;
}
return null;
}
public void m(){
System.out.println("m");
}
public static void main(String[] args) {
Mgr01 m1 = Mgr01.getInstance();
Mgr01 m2 = Mgr01.getInstance();
System.out.println(m1 == m2);
}
}
懒汉式单例
public class Mgr03 {
// 懒汉式单例
private static Mgr03 INSTANCE;
private Mgr03(){
}
public static Mgr03 getInstance(){
if(INSTANCE == null){
try {
Thread.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
INSTANCE = new Mgr03();
}
return INSTANCE;
}
public void m(){
System.out.println("m");
}
public static void main(String[] args) {
for (int i=0;i<100;i++){
new Thread (() -> {
System.out.println(Mgr03.getInstance().hashCode());
}).start();
}
}
}
懒汉式会出现线程不安全问题
其实我们本意不想让他返回新的对象了。因为对象为空就创建一个新对象。
所以这里在getInstance方法处增加synchronized 能保证线程安全问题?
结果还是不能
懒汉式同步代码块实现
public class Mgr05 {
// 懒汉式同步代码块
private static Mgr05 INSTANCE;
private Mgr05(){
}
public static Mgr05 getInstance(){
if (INSTANCE == null){
synchronized (Mgr05.class){
try {
Thread.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
INSTANCE = new Mgr05();
}
}
return INSTANCE;
}
public void m(){
System.out.println("m");
}
public static void main(String[] args) {
for (int i = 0;i<100;i++){
new Thread(() -> {
System.out.println(Mgr03.getInstance().hashCode());
}).start();
}
}
}
那他这个怎么去控制保证线程安全问题
答案是synchronized同步方法 + volatile线程可见
public class Mgr06 {
// synchronized + volatile 解决懒汉式单例线程安全问题
private static volatile Mgr06 INSTANCE;
private Mgr06(){
}
public synchronized static Mgr06 getInstance(){
if (INSTANCE == null){
try{
Thread.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
INSTANCE = new Mgr06();
}
return INSTANCE;
}
public void m(){
System.out.println("m");
}
public static void main(String[] args) {
for(int i = 0 ;i<1000;i++){
new Thread(() -> {
System.out.println(Mgr06.getInstance().hashCode());
}).start();
}
}
}
作者:zhqu4399
链接:http://www.javaheidong.com/blog/article/114326/b9eb89b212b599ea8c08/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!