6.18Java多线程并发、同步性能分析
作者:互联网
6.18Java多线程并发、同步性能分析
对比同步块和同步方法--->粒度更小的锁定资源,尽可能地提升性能
根据几个同步锁对象不同的实例观察线程不安全的实例
package iostudy.synchro;
/**
* 测试同步方法和同步块对粒度更小地资源锁定
* 感受性能上地差异
* @since JDK 1.8
* @date 2021/06/18
* @author Lucifer
*/
public class SynBlockTestNo3 {
public static void main(String[] args) {
/*资源实现类*/
SynWeb12306 synWeb12306 = new SynWeb12306();
/*多个线程代理对象*/
new Thread(synWeb12306, "代劳").start();
new Thread(synWeb12306, "一楼").start();
new Thread(synWeb12306, "丙楼").start();
}
}
/**
* 创建内部资源类
*/
class SynWeb12306 implements Runnable{
/*设置资源数量*/
private int ticketNums = 10;
private boolean flag = true;
/*重写接口run方法,实现具体逻辑*/
@Override
public void run(){
while (flag){
/*模拟线程等待*/
try {
Thread.sleep(100);
}catch (InterruptedException e){
System.out.println(e.getMessage());
e.printStackTrace();
}
/*调用内部具体实现逻辑的方法*/
test3();
}
}
/**
* 写一个内部具体实现逻辑的方法
* 同步方法
*/
public synchronized void test1(){
if (ticketNums<0){
/*开关改变*/
flag = false;
/*结束方法*/
return;
}
/*模拟延时*/
try {
Thread.sleep(200);
}catch (InterruptedException e){
System.out.println(e.getMessage());
e.printStackTrace();
}
/*获取线程名称、资源数量减少*/
System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--);
}
/**
* 写另一个一样逻辑的实现方法
* 同步块
*/
public void test2(){
/*明确锁的对象为资源对象*/
synchronized (this){
if (ticketNums<0){
/*开关改变*/
flag = false;
/*结束方法*/
return;
}
/*模拟延时等待*/
try {
Thread.sleep(200);
}catch (InterruptedException e){
System.out.println(e.getMessage());
e.printStackTrace();
}
/*获取当前线程名称和资源数量*/
System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--);
}
}
/*只锁定资源*/
/**
* 这样锁会不安全,导致数据不准确
* 原因是因为ticketNums这个资源是会变的,在锁资源的时候大的对象不能变动,里面的资源随便变化
* 大的对象不变,小的资源对象不变。
* 搞清楚对象在变和对象的属性在变的区别
*/
public void test3(){
/*明确锁的对象为资源对象*/
synchronized ((Integer) ticketNums){
if (ticketNums<0){
/*开关改变*/
flag = false;
/*结束方法*/
return;
}
/*模拟延时等待*/
try {
Thread.sleep(200);
}catch (InterruptedException e){
System.out.println(e.getMessage());
e.printStackTrace();
}
/*获取当前线程名称和资源数量*/
System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--);
}
}
}
粒度更小的锁提升性能
/*只锁定对象的属性--->缩小区域--->还是会有线程不安全问题。范围太小锁不住*/
/*小粒度锁定资源观察数据是否安全*/
public void test4(){
/*只锁定this的ticketNums属性*/
synchronized (this){
if (ticketNums<0){
/*开关变化*/
flag = false;
/*结束方法*/
return;
}
}
/*模拟网络延迟*/
try {
Thread.sleep(200);
}catch (InterruptedException e){
System.out.println(e.getMessage());
e.printStackTrace();
}
/*获取当前线程名称以及资源数量*/
System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--);
}
/*锁定范围太大--->损耗性能资源*/
/**
* 写另一个一样逻辑的实现方法
* 同步块
*/
public void test2(){
/*明确锁的对象为资源对象*/
synchronized (this){
if (ticketNums<0){
/*开关改变*/
flag = false;
/*结束方法*/
return;
}
/*模拟延时等待*/
try {
Thread.sleep(200);
}catch (InterruptedException e){
System.out.println(e.getMessage());
e.printStackTrace();
}
/*获取当前线程名称和资源数量*/
System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--);
}
}
double checking保证数据安全
/**
* 写另一个一样逻辑的实现方法
* 同步块,缩小锁定范围
*/
public void test5(){
/*明确锁的对象为资源对象*/
if (ticketNums<0){
/*开关改变*/
flag = false;
/*结束方法*/
return;
}
/*
上面的部分考虑的是没有票的情况
如果有多个线程进来最开始拦截不住还是会出现数据不安全的情况
*/
/*只锁定下面部分的范围*/
synchronized (this){
if (ticketNums<0){
/*开关改变*/
flag = false;
/*结束方法*/
return;
}
/*
这里加入判断考虑最后一张票的情况
*/
/*模拟延时等待*/
try {
Thread.sleep(200);
}catch (InterruptedException e){
System.out.println(e.getMessage());
e.printStackTrace();
}
/*获取当前线程名称和资源数量*/
System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--);
}
/*
尽可能地考虑锁合理地范围不是指代码地数量而是指数据地完整性
--->双重检测(double checking)
线程安全
两个检查,第一个检查不用锁定,第二个检查需要锁定
*/
}
标签:6.18,Java,Thread,ticketNums,System,线程,println,多线程,out 来源: https://www.cnblogs.com/JunkingBoy/p/14900984.html