多线程共享资源问题演示

这篇文章是根据  http://www.tianshouzhi.com/api/tutorials/mutithread/67做的一些测试总结:

java四种同步块:

1.实例方法同步

注意:注意:多个线程要运行的是同一个对象实例的同步方法,如果一个每个线程运行的是不同的对象实例的同步方法,是没有同步效果的,因为每个对象实例是把自身当成锁,就导致没有公用一个锁。

测试代码:

public class Two {
    private int count = 0;
    public synchronized   void add(){
        this.count++;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }


    // test
    public static void main(String[] args) throws InterruptedException{
        final Two t1 = new Two();
        final Two t2 = new Two();

        for(int i = 0; i < 10; i++){
            new Thread(){
                @Override
                public void run() {
                    for(int j = 0; j < 100; j++){
                        t1.add();
                        t2.add();;
                    }

                }
            }.start();
        }
        Thread.sleep(10000);
        System.out.println("t1.count = " + t1.count);
        System.out.println("t2.count = " + t2.count);
    }
}
测试结果:

t1.count = 1000
t2.count = 1000

如果我们把上面的 public synchronized void add改写成 public void add,那么测试结果为:

t1.count = 983
t2.count = 965

可以看到每个实例的add方法并不是线程安全的,那么如果我们把count这个变量改写成类变量(static int count = 0;)同时add方法加上synchronized关键字呢?

测试结果:

t1.count = 1934
t2.count = 1934

因为是类成员变量,所以实际上+的都是同一个变量。


2.静态方法同步

上面最后一个例子我们看到,将count声明为类成员变量,结果不是2000,而是1934。这是因为虽然count为类成员变量,但是add方法还是实例的同步方法,这就会造成线程不安全,这时我们可以将add方法声明为静态方法同步

测试代码:

public class Two {
    static int count = 0;
    public static synchronized void add(){
        count++;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }


    // test
    public static void main(String[] args) throws InterruptedException{
        final Two t1 = new Two();
        final Two t2 = new Two();

        for(int i = 0; i < 10; i++){
            new Thread(){
                @Override
                public void run() {
                    for(int j = 0; j < 100; j++){
                        t1.add();
                        t2.add();;
                    }

                }
            }.start();
        }
        Thread.sleep(10000);
        System.out.println("t1.count = " + t1.count);
        System.out.println("t2.count = " + t2.count);
    }
}

测试结果:

t1.count = 2000
t2.count = 2000

理想,线程安全。因为生命了静态的同步块也就保证了只允许一个线程执行同一个类中的静态同步方法,即使你是这个类的多个实例。


3.实例方法中的同步块

测试代码:

public class MyClass {
 
   public synchronized void log1(String msg1, String msg2){
      log.writeln(msg1);
      log.writeln(msg2);
   }
 
   public void log2(String msg1, String msg2){
      synchronized(this){
         log.writeln(msg1);
         log.writeln(msg2);
      }
   }
 }
在上例中,每次只有一个线程能够在两个同步块中任意一个方法内执行。如果第二个同步块不是同步在this实例对象上,那么两个方法可以被线程同时执行。其实像public synchronized void log1这个方法,内部也是用的synchronized(this)实例方法的同步块。


4.静态方法中的同步块
测试代码:

public class MyClass {
    public static synchronized void log1(String msg1, String msg2){
       log.writeln(msg1);
       log.writeln(msg2);
    }
 
    public static void log2(String msg1, String msg2){
       synchronized(MyClass.class){
          log.writeln(msg1);
          log.writeln(msg2);
       }
    }
  }
这两个方法不允许同时被线程访问。即使是同一个类的不同实例。如果第二个同步块不是同步在MyClass.class这个对象上。那么这两个方法可以同时被线程访问。











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值