静态成员变量/非静态成员变量在单例/多例 什么情况加锁

 

 

实体

public class Entity {

    private int count;

    public int getCount() {

        return count;

    }

    public void setCount(int count) {

        this.count = count;

    }

}

实体单例

public class Single {

    public static final Entity entity = new Entity();

    public static Entity getEntity() {

        return entity;

    }

}

创建两个线程

public class ThreadA extends Thread {

    Entity entity = Single.getEntity();

    public void run() {

        for (int i = 0; i < 5; i++) {

            entity.setCount(i);

            try {

                Thread.sleep(100);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println("A" + entity.getCount());

        }

    }

}



public class ThreadB extends Thread {

    Entity entity = Single.getEntity();

    public void run() {

        for (int i = 5; i < 10; i++) {

            entity.setCount(i);

            try {

                Thread.sleep(50);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println("B" + entity.getCount());

        }

    }

}

入口



public class Test {

    public static void main(String[] args) throws Exception {

        new ThreadA().start();

        new ThreadB().start();

    }

}

可能产生的一种输出结果是:

B0

B6

A7

B1

B8

A9

B2

A2

A3

A4

回头看我们的两个线程中的for偱环,可能错误的认为A线程只会产生A0 A1 A2 A3 A4 ,    B线程只会产生B5 B6 B7 B8 B9, 但很显然我们的输出中出现了  B0 ,A7等你意料之外的数据,这里就产生了线程不安全情况。我们把单例修改成多例试试,其它代码不变,只修改线程 A B的第一行代码:

public class ThreadA extends Thread {

    Entity entity = new Entity();

    public void run() {

        for (int i = 0; i < 5; i++) {

            entity.setCount(i);

            try {

                Thread.sleep(100);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println("A" + entity.getCount());

        }

    }

}



public class ThreadB extends Thread {

    Entity entity = new Entity();

    public void run() {

        for (int i = 5; i < 10; i++) {

            entity.setCount(i);

            try {

                Thread.sleep(50);

            } catch (InterruptedException e) {

                e.printStackTrace();

            }

            System.out.println("B" + entity.getCount());

        }

    }

}

 

运行结果如下:

B5

A0

B6

B7

A1

B8

B9

A2

A3

A4

 

数据正确,已通过多例控制线程安全,这个仅是在非static成员变量的情况,在多例情况下如果实体中的成员变量为static,修改实体代码

public class Entity {

    private static int count;

    public int getCount() {

        return count;

    }

    public void setCount(int count) {

        this.count = count;

    }

}

 

运行结果如下:

B5

A6

B1

B7

A8

B2

B9

A9

A3

A4

 

又出现了A6等意外数据,要解决这种线程不安全问题可使用ThreadLocal, 相比synchronized个人比较喜欢ThreadLocal, synchronized排队访问,ThreadLocal创建变更副本,ThreadLocal通过空间换时间。修改实体

public class Entity {

    private static ThreadLocal count = new ThreadLocal();

    public int getCount() {

        return count.get();

    }

    public void setCount(int count) {

        this.count.set(count);

    }

}

 

运行结果如下:

B5

A0

B6

B7

A1

B8

B9

A2

A3

A4

 

已线程安全化。(多例    static成员变量)

 

 

 

前面例子说到单例 非static成员变量的情况也会出现线程不安全,我们把线程A B第一行代码再次修改成

 

Entity entity = Single.getEntity();

 

实体的第一行代码 修改成非static成员变量

  private  ThreadLocal count = new ThreadLocal();

运行如下:

B5

A0

B6

B7

A1

B8

B9

A2

A3

A4

 

已完成线程安全化。 单例 static成员变量也是线程不安全,一样可以通过ThreadLocal线程安全化。

 

总之 单例  非static成员变量及static成员变量都是线程不安全, 多例 非static成员变量线程安全,但多例static成员变量会有线程不安全情况,

 

关于synchronized的实现还要考虑死锁等情况,下回有时间再写一下,本文有写的不好不对的地方请指出,大家一起探讨,谢谢!

 

 

————————————————

版权声明:本文为CSDN博主「逆流扬帆Lai」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/u014534811/article/details/50526057

你可能感兴趣的:(静态成员变量/非静态成员变量在单例/多例 什么情况加锁)