Java教程

6.18Java多线程并发、同步性能分析

本文主要是介绍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.18Java多线程并发、同步性能分析的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!