电子商务网站建设风格,实时新闻最新消息,做网站公司教程,龙岗做网站公司icxun作者#xff1a;爱塔居 专栏#xff1a;JavaEE 作者简介#xff1a;大三学生#xff0c;喜欢总结与分享~ 文章目录 目录 文章目录 章节回顾 一、wait 和notify 二、设计模式 2.1 单例模式 章节回顾
线程安全
1.一个线程不安全的案例#xff08;两个线程各自自增5w次爱塔居 专栏JavaEE 作者简介大三学生喜欢总结与分享~ 文章目录 目录 文章目录 章节回顾 一、wait 和notify 二、设计模式 2.1 单例模式 章节回顾
线程安全
1.一个线程不安全的案例两个线程各自自增5w次结果不是10w
2.线程不安全的原因
1抢占式执行随机调度。线程中的代码执行到任意一行都随意可能被切换出去。
2多个线程同时修改同一个变量。
3修改操作不是原子的。
4内存可见性volatile编译器可能会对我们的代码进行优化。
一个线程频繁读一个线程修改
5指令重排序。
除了这些原因还有其他原因。
3.解决方案 加锁
在线程1加锁的过程中线程2无法把自己的指令插入到线程1的修改过程中。
synchronized指定一个“锁对象”
4.volatile
关于volatile和内存可见性补充
内存可见性
t1频繁读取主内存效率比较低就被优化成直接读自己的工作内存。
t2修改了主内存的结果由于t1没有读主内存导致修改不能被识别到。
工作内存CPU寄存器
主内存内存
工作内存和主内存都是由英文work memory和main memory翻译来的。所以工作内存不一定非要是内存可以是记忆存储区不一定是特指“内存条”。
这一套说法也称为JMM(java memory model java是跨平台的。 1.兼容多种操作系统 2.兼容多种硬件设备 不同的硬件其实差别很大。cpu和cpu之间差别就会比较大。 像以前的cpu上面只有寄存器。现在的cpu上面还有缓存。 而且有的cpu缓存还有好几个L1,L2,L3,(现在常见的cpu都是3级缓存 工作内存准确来说代表cpu寄存器缓存CPU内部存储数据的空间 cpu读储存器速度比读内存快3-4个数量级。 缓存读取速度介于寄存器和内存之间。 L1最快空间最小仍然比寄存器慢 L3最快空间最大仍然比内存快很多 实际上cpu尝试读一个内存数据 1.先看寄存器里有没有 2.没有看L1有没有 3.没有看L2有没有 4.没有看L3有没有 5.没有看内存有没有 具体缓存的大小对于程序效率的影响也看实际的应用场景。 一、wait 和notify
线程的调度是无序的随机的。但是也是有一定的需求场景的希望线程有序执行。
join是一种控制顺序的方式但是功效有限。
wait就是让某个线程先暂停下来等一等。
wait主要做三件事
1.解锁
2.阻塞等待
3.当收到通知的时候就唤醒同时尝试重新获取锁。
notify就是把该线程唤醒能够继续执行。
wait和notify是Object的方法
只要你是个类对象不是内置类型/基本数据类型都是可以使用wait和notify。
public class test {static int i;public static void main(String argv[]) throws InterruptedException{Object lockernew Object();Thread t1new Thread(()-{while (true){try {System.out.println(wait 开始);synchronized (locker){locker.wait();}System.out.println(wait 结束);}catch (InterruptedException e){e.printStackTrace();}}});t1.start();Thread.sleep(1000);Thread t2new Thread(()-{synchronized (locker){System.out.println(notify 开始);locker.notify();System.out.println(notify 结束);}});t2.start();}
}使用外套阻塞等待会让线程进入WAITING状态。wait也提供了一个带参数的版本参数指定的是最大等待时间。不带参数的wait是死等带参数的wait就会等最大时间之后还没有人通知就自己唤醒自己。
wait会导致阻塞竞争锁也会导致阻塞两种不同的进入阻塞的方式。wait的初心就是为了实现阻塞的效果。
join只能是让t2的线程先执行完再继续执行t1一定是串行的
wait、notify可以让t2执行完一部分再让t1执行一部分再让t2去执行再……
唤醒操作还有一个notifyAll。可以有多个线程等待同一个对象。
比如在t1,t2,t3中都调用object.wait。此时在main中调用了object.notify 会随机唤醒上述的一个线程。另外两个仍然会是waiting状态
如果是调用了object.notifyAll,此时就会把上述三个线程都唤醒。伺候这三个线程就会重新竞争锁然后依次执行。 总结 1.wait需要搭配synchronized使用sleep不需要。 2.wait是Object的方法sleep是Thread的静态方法。 wait和sleep都是可以提前唤醒的。 他们最大的区别在于初心不同。 wait解决的是线程之间的顺序控制 sleep单纯是让当前线程休眠一会。 二、设计模式
设计模式就是软件开发中的棋谱。大佬们针对一些常见场景总结出来的代码的编写套路。设计模式有很多种。
在校招阶段主要考察两个设计模式。
1.单例模式
2.工厂模式
设计模式需要大家有一定的开发经验的积累才好理解。
2.1 单例模式
单例指的是单个实例instance对象。类的实例就是对象。Java中的单例模式借助java语法保证某个类只能够创建出一个实例而不能new多次。
有些场景本身就是要求某个概念是单例的。
//把这个类设定为单例
class Singleton{//唯一的实例的实体
private static Singleton instancenew Singleton();
//被static修饰该属性是类的属性。JVM中每个类的类对象只有唯一一份类对象里的这个成员自然也是唯一一份了。
//获取到实例的方法public static Singleton getInstance(){return instance;}//禁止外部new实例private Singleton(){};
}
public class test {public static void main(String[] args) {Singleton s1Singleton.getInstance();Singleton s2Singleton.getInstance();}}
java中实现单例模式是有多种写法的。
主要说两种
1.饿汉模式急迫
2.懒汉模式从容
A吃完饭立马洗碗饿汉行为
B吃完饭不洗碗等下一顿要用碗的时候再洗碗。懒汉行为
通常认为懒汉模式更好效率更高。非必要不洗碗
举一个计算机的例子
打开一个硬盘上的文件读取文件内容并显示出来。
饿汉把文件所有内容都读到内存中并显示出来
懒汉只把文件读一小部分把当前的屏幕填充上如果用户翻页再读其他文件内容。
当文件特别大的时候就可以看出懒汉模式的优势了。
饿汉模式
//把这个类设定为单例饿汉
class Singleton{//唯一的实例的实体
private static Singleton instancenew Singleton();
//被static修饰该属性是类的属性。JVM中每个类的类对象只有唯一一份类对象里的这个成员自然也是唯一一份了。
//获取到实例的方法public static Singleton getInstance(){return instance;}//禁止外部new实例private Singleton(){};
}
public class test {public static void main(String[] args) {Singleton s1Singleton.getInstance();Singleton s2Singleton.getInstance();}}
懒汉模式
//把这个类设定为单例模式中的懒汉模式。
class SingletonLazy{
private static SingletonLazy instancenull;public static SingletonLazy getInstance(){if(instancenull){instancenew SingletonLazy();}return instance;}private SingletonLazy(){};
}
public class test {public static void main(String[] args) {SingletonLazy s1SingletonLazy.getInstance();SingletonLazy s2SingletonLazy.getInstance();System.out.println(s1s2);}} 饿汉模式一开始就把实例创建好了而懒汉模式是非必要不创建实例。
上述两个代码是否是线程安全的多个线程下调用getInstance是否会出现问题
饿汉模式认为是线程安全的只是读数据。
而在多线程下懒汉模式可能无法保证创建对象的唯一性。
比如以下情况 如何解决上诉线程安全问题
进行加锁保证判定和new操作是原子性的。
//把这个类设定为单例模式中的懒汉模式。
class SingletonLazy{
private static SingletonLazy instancenull;synchronized public static SingletonLazy getInstance(){if(instancenull){instancenew SingletonLazy();}return instance;}private SingletonLazy(){};
}
public class test {public static void main(String[] args) {SingletonLazy s1SingletonLazy.getInstance();SingletonLazy s2SingletonLazy.getInstance();System.out.println(s1s2);}}