别人做的网站不能用怎么办,巴中交通建设有限公司网站,客户关系管理的重要性,电商运营 网站运营1.线程不安全分析
#xff08;1#xff09;线程不安全的主要原因就是#xff0c;系统的抢占式执行#xff0c;对于内核设计者来说#xff0c;这是非常方便的一个执行方式#xff0c;但是这却却导致线程不安全的问题#xff0c;也有不抢占执行的系统#xff0c;但是这种…1.线程不安全分析
1线程不安全的主要原因就是系统的抢占式执行对于内核设计者来说这是非常方便的一个执行方式但是这却却导致线程不安全的问题也有不抢占执行的系统但是这种系统会导致你的系统性能不是特别好。
2多个线程执行操作一个对象不会发生线程不安全的情况 3String之所以设置成无法改变也是为了线程安全如果想改可以试一试反射
4为了更好的解决线程不安全问题我们可以将非原子操作改成原子操作这个月就可以更安全的保证线程的安全
2.锁
2.1锁的定义
1锁可以理解成解锁上锁这个操作拿到锁以后就可以使你的线程互斥只有这个线程搞完然后释放锁然后需要的线程拿到锁以后才能继续执行后序的操作。 2在一个程序中可以有多把锁只有对一个非原子事物进行加锁才会发生互斥这个情况
图解 2.2锁的简单总结 2.3锁的具体实现代码
1创建一个类型Object由于Object类是所有类的父类所以所有类都可以拿到以Object枷锁的锁。这种设定是不太合理的
在python中以及c中能够加锁的是非常少的。
2锁的格式
这个锁是同步的同步的反义词就是独占 3锁的注意事项 (4)在使用sychronized方法进入到了大括号中就是加锁了当这个大括号中的运行结束以后就会自动的解锁其他的语言也是这样的
2.4锁的互斥
如果两个线程对对同一个对象进行加锁就会发生互斥对两个不同的对象进行加锁就不会发生互斥。
1代码互斥 这种情况就是两个线程同时用一把锁对线程进行加锁这时候就会发生互斥程序会直接终止 2代码不互斥 用两把锁对其进行加锁这时候就可以避免互斥了 2.5图集锁的互斥 这个拿到锁的过程可以理解为我约会一个女生这个女生同意了这个时候女生就是被我上锁了这时候要是其他男生来就会被阻塞约会不了
2.6代码实例
1代码
package thread;class Counter {private int count 0;synchronized public void add() {count;}public static void func() {synchronized (Counter.class) {// ....}}public int get() {return count;}
}public class Demo20 {public static void main(String[] args) throws InterruptedException {Counter counter new Counter();Counter counter2 new Counter();// Object locker new Object();Thread t1 new Thread(() - {for (int i 0; i 50000; i) {// counter.add();counter.func();}});Thread t2 new Thread(() - {for (int i 0; i 50000; i) {// counter2.add();counter2.func();}});t1.start();t2.start();t1.join();t2.join();System.out.println(count counter.get());}
}我们可以用counter这个类来进行加锁对于java来说锁只是一个标准只要加锁的对象是一样的就行了。
其中我们也可以用this来进行加锁这个方法也是不错的相当于简化直接在括号里面写一个this。
3.锁的扩展用法
1针对类的类对象进行加锁 2通过反射来拿到当作锁的类的信息并进行加锁类似于加锁继承 其中我们要注意的就是如果在多个线程对这个func方法进行调用这时候就会发生锁竞争。
3解决方式 加锁这个func中的方法当这个锁使用这个方法的时候相当于是this这个对象在使用func中的方法的这个对象这时候就不会发生锁的竞争。 2.5锁的嵌套 4对对象加锁使用对象中的方法发生锁竞争的情况。 5我们也可以使用静态方法来进行加锁实现但是我并不是很推荐
4.锁的要记住的东西 3.死锁问题的出现
3.1小练习来判断这个代码是否有问题可能有问题也是算的
1
这种写法也会可能出现问题两个线程可能发生的问题有t1执行完毕了但是t2还在执行这时候就会变成串行执行 2 这串代码乍一眼看上去是没毛病但是其实他是有问题的for循环中的i的值会被锁锁住所以可能会出现下面的情况{t1在执行的过程中t2已经执行完毕了这时候t2的i就会把t1的i给覆盖这时候就会出现问题}
3特殊情况可重入锁 3.2synchronized为什么这么智能不会被死锁
1 当一个线程已经获得了锁并再次请求同一个锁时JVM不会立即释放第一个锁再重新获取。相反它会继续持有这个锁而不会导致阻塞。这种情况被称为重入锁。因此即使同一个线程多次请求同一个锁它也不会释放锁再重新获取而是继续持有锁。
另一方面如果一个线程尝试获取一个已经被其他线程持有的锁那么它将被阻塞直到锁可用。这种行为是由JVM的线程调度器和对象监视器来管理的。 3.3可重入锁的作用
可重入锁相当于保护你的这个线程的安全如果用了这个线程以外的锁就会将这个锁进行阻塞这样可以更好的保证你的线程安全
4.死锁会出现的3个场景
1
2场景而就是有两个线程两把不同的锁两个线程分别需要另一个线程解锁释放的锁才能执行下一步这时候就会发生死锁
3第三个场景就是第二个场景的升级版本
代码
5.小知识
1.如果需要查看哪个线程需要哪一把锁我们可以用idea中自带的软件来查找这个线程是持有的哪一把锁。画圆圈的就是这些线程获取到的锁以及这个线程的状态是什么也可以找到。 2.死锁发生的条件必须要背下来的小知识必须要背下来 3.多个线程要用锁的时候只需要将所得顺序约定好然后挨个加锁就行了大致提一下后序会详细讲解
5.引起线程不安全的主要原因
1内存的可见性是可能使得线程发生线程的不安全问题。 接下来我会写一段代码来对这种情况来进行详细的讲解。
两个线程分别是用来读和写的但是我们会发现输入的是0但是却没有将线程1给停止。
接下来我会用图解的形式给大家详细的讲解 2首先我要先给大家讲解一个东西当一个计算机对一个数据进行读取的或者比较的时候是三个操作的。
3load先从内存中读取数据到cpu寄存器中
4cmp比较同时会产生跳转条件成立的时候就会继续顺序执行条件不成立的时候就会跳转到另一个地址上面来进行执行。
5其中我们要注意在循环中这种操作的速度是非常快的短时间会出现大量的load和cmp反复执行的效果
而且load执行消耗的时间会比cmp多很多
多个几千倍上万倍
6在上面代码的过程中load的速度非常慢执行一次load消耗的时间顶成千上万倍的load的次数
7另外JVM还会每次发现load的执行结果是一样的为空这时候JVM就会直接把load的操作直接优化了读取到的结果将会是空。所以这就会使得循环不会被终止相当于裁员
(8)其中要注意的就是IO操作注定是反复hi下的结果是不相同的所以IO操作是不会被优化掉的IO操作是在load然后cmp之后的操作。
4.解决方式
关键字volatile只要用这个关键字进行修饰就让JVM知道这一部分是不需要进行优化的。
有些人想既然不优化的化不会发生这种事情那么JVM干嘛要进行优化给大家举一个简单的例子如果进行优化了那么这个线程将会比以前的速度快十倍多
6.线程饿死wait关键字
我们用wait关键字就代表着