"诡异的线程不安全",代码块,同步代码块,对象锁

上一节课我们学习了java的多线程,ArrayList线程不安全和Vector线程安全
这节课我门改变一下
不在主线程里面打印出mylist的长度了而是在子线程中打印mylist的长度
代码改为下面
MyIndex里面


image.png

MyThread下面


image.png

运行结果
image.png

出现了线程不安全的情况 我们在代码中使用的是Vector集合为什么会出现线程不安全的情况呢?
为了解决这个问题 我们需要在子线程外部中加入一个代码块 这个代码块为同步代码块
代码如下
image.png

加入同步代码块,将list对象锁住 即可以解决线程不安全问题
运行结果


image.png

运行多次 结果相同
接下来我们把Vector换成ArrayList试一下
MyIndex文件中
image.png

运行结果
image.png

接下来我们了解一下代码块
image.png

代码块就是用{}括起来的部分组成个代码块 代码块是有块级作用域的 嵌套的代码块子代码块可以访问父代码块里的内容
在我们的MyIndex里面写入如下
image.png

可以看见输出内容处a报错了 这就是代码块的作用域 外部访问不到a
但是写成下面这样
image.png

就不报错了

运行结果


image.png

嵌套代码块子代码块可以访问父代码块里的a
一般我们在方法中不会这样写,因为可读性并不高
image.png

那么代码块主要用在哪里呢?
1.在类里面
构造代码块
image.png

为了演示我们在Core里创建个test文件
image.png

代码如下
image.png

这时我们在MyIndex里面使用一下
image.png

运行结果
image.png

可以看出将构造代码块放在上面 构造代码块先执行了
接下来在我们test文件里加入一个构造代码块
image.png

运行结果
image.png

接下来在test中将代码块1和2位置互换
image.png

运行结果
image.png

静态代码块
image.png

用static关键字加上大括号包起来的代码块
静态代码块只会执行一次
为什么只会执行一次呢?
下面看一下代码 test文件中
image.png

运行结果
image.png

可以看到静态代码块先执行了

但是我们要知道 静态代码块 和 构造代码块 构造函数并不在同一阶段执行
接下来我们演示一下 在MyIndex里面多实例化几次test
代码如下


image.png

运行结果
image.png

静态代码块只会执行一次是因为他只在类的初始化阶段执行 而构造代码块和构造函数在类的实例化阶段执行
还有一个有趣的现象是
image.png

演示一下 test中代码定义一个静态变量
image.png

这时如果我不在MyIndex里面实例化代码
运行结果如下
image.png

什么都没输出 因为我没实例化
其实类装载是有过程的 装载-》验证-》解析-》初始化-》实例化等过程
但是我们在MyIndex里面调用一下name
image.png

运行结果
image.png

可以看见执行了静态代码块里面的内容 因为我们对变量进行调用了 触发了类装载的过程了
接下来再看下同步代码块
image.png

image.png

同步代码块 其中Vector里面有sync那个同步方法 为什么还会出现线程不安全 为什么需要在子线程里面将list锁住呢
问题在于什么时候释放锁 是因为Vector代码中锁释放的时间不一样 Vector中锁的是this对象Vector实例化过后的对象
其中Vector里面有一个add方法 这个方法执行完之后 锁就释放了 这时另外一个线程对list操作的时候 就可以得到锁了 所以会出现得到size结果不一致的现象
但是我在MyThread中加入同步代码块时 需要将同步代码块中的内容执行完毕 才释放锁
也就是我们下面的代码
image.png

这时add执行完成之后 去计算mylist的长度时锁还没被释放
接下来我们在Core里面建一个MyObj.java文件
image.png

接下来修改一下MyThread线程代码
使其支持两个方法 先不使用ArrayList和Vector 先传入MyObj参数
image.png

接下来来到MyIndex.java文件
实例化MyObj 传入子线程
image.png

依然对MyThread循环500次 看一下运行效果 等一下要修改一下MyObj里面的源码(因为ArrayList里面没法改)
image.png

运行结果
image.png

出现了线程不安全
接下来在MyObj里面函数部分加入同步关键字synchronized
image.png

运行结果
image.png

依然还是线程不安全的
那么如何解决呢?
这时来到MyThread类
image.png

加入同步代码块 将myObj锁住 一旦锁住之后 代码块里面的内容只能有一个线程执行 下一个线程只有等上一个线程执行完成之后才能执行
运行结果一定是500的倍数
结果如下
image.png

但是如果我们不想使用同步代码块怎么办呢?
MyThread里面
image.png

MyObj里面
image.png

运行结果
image.png

这里只能保证运行结果是500的倍数 因为是两个同步代码方法
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。 首先讲...
    李欣阳阅读 2,510评论 1 15
  • Java多线程学习 [-] 一扩展javalangThread类 二实现javalangRunnable接口 三T...
    影驰阅读 2,998评论 1 18
  • 一、进程和线程 进程 进程就是一个执行中的程序实例,每个进程都有自己独立的一块内存空间,一个进程中可以有多个线程。...
    阿敏其人阅读 2,626评论 0 13
  • 该文章转自:http://blog.csdn.net/evankaka/article/details/44153...
    加来依蓝阅读 7,385评论 3 87
  • 侄女大概六七岁左右,也是一名留守儿童,家里的奶奶带着她,性格很是内向,甚至有一点怪癖,我回家的那天正好遇到她在桥头...
    无_念阅读 536评论 2 3