多线程基础学习七:使用synchronized实现多线程情况下的访问次数统计

来源:互联网 发布:单片机psw 编辑:程序博客网 时间:2024/06/06 18:04

前面学习了多线成基础和synchroniezed的基本用法,现在两者结合起来使用,实现一个简单的计数需求。

需求

多个线程访问某个类,统计类的访问次数并输出。

实现

正确的写法

第一种实现方式:

public class SynchronizedCountNum {    public static void main (String[] args) {        int i = 0;        while (i < 10) {            Thread test = new CountThread();            test.start();            i++;        }        //SleepUtil.sleep(10000);        //System.out.println(Test.num);    }    static  class CountThread extends  Thread {        @Override        public void run () {            Test.doSomething();        }    }    static class Test {        public  static  int num = 0;        public  synchronized static void doSomething() {            num++;            SleepUtil.sleep(1000);// 模拟做事            System.out.println(num);        }    }}

输出结果:

12345678910

从执行过程可以看出来,这种方式是每次只能一个线程执行doSomething方法,所以结果是正确,总共访问了10次。

第二种实现方式:

public class SynchronizedCountNum {    public static void main (String[] args) {        int i = 0;        while (i < 10) {            Thread test = new CountThread();            test.start();            i++;        }        //SleepUtil.sleep(10000);        //System.out.println(Test.num);    }    static  class CountThread extends  Thread {        @Override        public void run () {            Test.doSomething();        }    }    static class Test {        public  static  int num = 0;        public   static void doSomething() {            synchronized(Test.class) {                num++;                SleepUtil.sleep(1000);// 模拟做事                System.out.println(num);            }        }    }}

输出结果:

12345678910

这样写结果也是对的,从执行上,效果和上面那种写法一样,都是逐一执行。

第三种写法:

public class SynchronizedCountNum {    public static void main (String[] args) {        int i = 0;        while (i < 10) {            Thread test = new CountThread();            test.start();            i++;        }        //SleepUtil.sleep(10000);        //System.out.println(Test.num);    }    static  class CountThread extends  Thread {        @Override        public void run () {            Test.doSomething();        }    }    static class Test {        public  static  int num = 0;        public   static void doSomething() {            synchronized(Test.class) {                num++;                System.out.println(num);            }            SleepUtil.sleep(1000);// 模拟做事        }    }}

输出结果:

12345678910

这种写法只在计数的代码上加了同步,做事过程不需要同步,这样的情况下计数结果也是对的。

错误的写法

第一种写法:

public class SynchronizedCountNum {    public static void main (String[] args) {        int i = 0;        while (i < 30) {            Thread test = new CountThread();            test.start();            i++;        }        //SleepUtil.sleep(10000);        //System.out.println(Test.num);    }    static  class CountThread extends  Thread {        @Override        public void run () {            Test.doSomething();        }    }    static class Test {        public  static  int num = 0;        public   static void doSomething() {            num++;            System.out.println(num);            SleepUtil.sleep(4000);// 模拟做事        }    }}
378139145156163341718121911102120222324252627282930

可以直观看到出现3个3,很显然是错误的;但是如果只睡眠1-3秒,执行了很多次,才会出现错误的结果,大多数的情况下都是正确的结果,当睡眠时间继续增加时,错误的结果出现的频率非常高。

第二种写法:

public class SynchronizedCountNum {    public static void main (String[] args) {        int i = 0;        while (i < 30) {            Thread test = new CountThread();            test.start();            i++;        }        //SleepUtil.sleep(10000);        //System.out.println(Test.num);    }    static  class CountThread extends  Thread {        @Override        public void run () {            Test.doSomething();        }    }    static class Test {        public  static  int num = 0;        public   static void doSomething() {            synchronized (Test.class) {                num++;            }            System.out.println(num);            SleepUtil.sleep(4000);// 模拟做事        }    }}

输出结果:

345783396101112131415161718192021222324252627282930

结果中没有1 、2 ,有三个3,这个结果也是错误的。

总结

能保证输出正确结果的写法都是保证修改和读取数据都在同步中(读取数据的时候,值不会被其它线程修改),而不能保证输出正确结果的写法都是修改数据和读取数据不在同步中(也就是说读取的时候,值可能被其它线程修改了)。

阅读全文
0 0
原创粉丝点击