Java 阻塞与非阻塞性能简单对比思考

使用三个线程分别打印a、b、c三个字母,要求三个字母按照顺序打印指定次数,通过模拟线程不同的消耗时间来对比使用wait和不使用wait的性能的差异。

模拟每个线程只执行短暂时间

public class Test1 {
    private static int status = 1;
    private static int times = 100000;
    private static Object obj = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 =  new Thread(() -> {
            while (times > 1) {
                while (status != 1) {
                }
                System.out.print("A");
//                try {
//                    Thread.sleep(10);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                status = 2;
            }
        });

        Thread thread2 = new Thread(() -> {
            while (times > 1) {
                while (status != 2) {
                }
                System.out.print("B");
//                try {
//                    Thread.sleep(10);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                status = 3;
            }
        });

        Thread thread3 = new Thread(() -> {
            while (times > 0) {
                while (status != 3) {
                }
                System.out.println("C");
//                try {
//                    Thread.sleep(10);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                status = 1;
                times--;
            }
        });

        long start = System.currentTimeMillis();
        thread1.start();
        thread2.start();
        thread3.start();

        thread1.join();
        thread2.join();
        thread3.join();
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}

在这里插入图片描述

public class Test2 {

    private static int status = 1;
    private static int times = 100000;
    private static Object obj = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 =  new Thread(() -> {
            while (times > 1) {
                while (status != 1) {
                    synchronized (obj) {
                        try {
                            obj.notifyAll();
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                System.out.print("A");
//                try {
//                    Thread.sleep(10);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                status = 2;
            }
            synchronized (obj) {
                obj.notifyAll();
            }
        });

        Thread thread2 = new Thread(() -> {
            while (times > 1) {
                while (status != 2) {
                    synchronized (obj) {
                        try {
                            obj.notifyAll();
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                System.out.print("B");
//                try {
//                    Thread.sleep(10);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                status = 3;
            }
            synchronized (obj) {
                obj.notifyAll();
            }
        });

        Thread thread3 = new Thread(() -> {
            while (times > 0) {
                while (status != 3) {
                    synchronized (obj) {
                        try {
                            obj.notifyAll();
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                System.out.println("C");
//                try {
//                    Thread.sleep(10);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
                status = 1;
                times--;
            }
        });

        long start = System.currentTimeMillis();
        thread1.start();
        thread2.start();
        thread3.start();

        thread1.join();
        thread2.join();
        thread3.join();
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}

在这里插入图片描述

在这里插入图片描述

Test1与Test2的运行时间进行对比可以发现Test2使用wait需要更长的运行时间,而Test1循环等待需要耗费更少的时间,在CPU使用率图上左边为运行Test1时的CPU使用率,右边为Test2的CPU使用率,虽然不是百分百准确,但是总体上可以看出二者的运行时CPU使用率相差不大。

线程需要运行相对较长时间情况

通过在两个线程运行中间加入睡眠时间,模拟线程需要长时间运行的情况

public class Test1 {
    private static int status = 1;
    private static int times = 1000;
    private static Object obj = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 =  new Thread(() -> {
            while (times > 1) {
                while (status != 1) {
                }
                System.out.print("A");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                status = 2;
            }
        });

        Thread thread2 = new Thread(() -> {
            while (times > 1) {
                while (status != 2) {
                }
                System.out.print("B");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                status = 3;
            }
        });

        Thread thread3 = new Thread(() -> {
            while (times > 0) {
                while (status != 3) {
                }
                System.out.println("C");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                status = 1;
                times--;
            }
        });

        long start = System.currentTimeMillis();
        thread1.start();
        thread2.start();
        thread3.start();

        thread1.join();
        thread2.join();
        thread3.join();
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}

在这里插入图片描述

public class Test2 {

    private static int status = 1;
    private static int times = 1000;
    private static Object obj = new Object();

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 =  new Thread(() -> {
            while (times > 1) {
                while (status != 1) {
                    synchronized (obj) {
                        try {
                            obj.notifyAll();
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                System.out.print("A");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                status = 2;
            }
            synchronized (obj) {
                obj.notifyAll();
            }
        });

        Thread thread2 = new Thread(() -> {
            while (times > 1) {
                while (status != 2) {
                    synchronized (obj) {
                        try {
                            obj.notifyAll();
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                System.out.print("B");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                status = 3;
            }
            synchronized (obj) {
                obj.notifyAll();
            }
        });

        Thread thread3 = new Thread(() -> {
            while (times > 0) {
                while (status != 3) {
                    synchronized (obj) {
                        try {
                            obj.notifyAll();
                            obj.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                System.out.println("C");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                status = 1;
                times--;
            }
        });

        long start = System.currentTimeMillis();
        thread1.start();
        thread2.start();
        thread3.start();

        thread1.join();
        thread2.join();
        thread3.join();
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}

在这里插入图片描述
在这里插入图片描述
通过对比我们可以看出当线程需要运行长时间的时候使用wait和不使用wait进行循环的运行时间相差不多,但是从CPU使用率来看,Test2需要的CPU几乎是Test1的一半。

思考

1.当线程运行时间较短能较块释放锁时使用自旋锁需要的资源相对较少同时响应较块,当线程需要运行较长时间时,通过获取锁的方式让线程调用wait方法让线程进行等待,减少自旋时对资源的过度消耗。
2.java中synchronize对锁进行分级,分为无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态,当调用的线程数增加时对锁进行升级。偏向锁:当只有一个线程访问该类时不进行加锁操作。轻量级:当有两个线程访问同一个类时,对锁进行升级,轻量级锁使用自选的方式进行等待。重量级锁:当多个线程访问同一个类时需要线程阻塞等待。java对锁的分级的原理也是类似,当两个线程访问同一个类时使用自选可以快速获得类的使用权,当多个线程访问同一个类时不能快速获得类的使用权,所以根据情况对锁进行升级,提高运行速度。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值