变量的同步

问题描述:

在这个程序中,对象jai被一个线程访问,同时它也被另一个线程修改。这是正确的工作方式吗?是否不需要使对象同步?变量的同步

public class SameObjectModification { 

    private static int i = 0; 

    private static Jai jai; 

    static class Jai { 

     private final int a; 

     public Jai(int a) { 
      this.a = a; 
     } 

     public void print() { 
      System.out.println("value ==> " + a); 
     } 
    } 

    public static void main(String[] args) { 

     Thread t1 = new Thread() { 

      @Override 
      public void run() { 
       while (true) { 
        if (jai != null) 
         jai.print(); 
       } 
      } 
     }; 

     Thread t2 = new Thread() { 

      @Override 
      public void run() { 
       while (true) { 
        jai = new Jai(i++); 
       } 
      } 
     }; 

     t1.start(); 
     t2.start(); 
    } 
} 
+0

你想达到什么目的? – aioobe 2015-02-23 10:22:09

+1

不,不是。您正在从不同的线程访问状态。所以你会有可见性问题。 – 2015-02-23 10:23:39

+0

这取决于你想要的。如果你想实现互斥,那么你必须同步它。 – 2015-02-23 10:39:06

目前尚不清楚你试图达到什么目标,但是你可以通过使用原子来获得每个Jai的唯一值。

private static AtomicInteger i = new AtomicInteger(0); 

private static Jai jai; 

static class Jai { 

    private int a; 
    public Jai() { 
     this.a = i.incrementAndGet(); 
    } 

这thrade保存例如

private static int i = 0; 

private static AtomicReference<Jai> jai = new AtomicReference<Jai>(); 

static class Jai { 

    private final int a; 

    public Jai(int a) { 
     this.a = a; 
    } 

    public void print() { 
     System.out.println("value ==> " + a); 
    } 
} 

public static void main(String[] args) { 

    Thread t1 = new Thread() { 

     @Override 
     public void run() { 
      while (true) { 
       Jai tmp = jai.get(); 
       if (tmp != null) 
        tmp.print(); 
      } 
     } 
    }; 

    Thread t2 = new Thread() { 

     @Override 
     public void run() { 
      while (true) { 
       jai.set(new Jai(i++)); 
      } 
     } 
    }; 

    t1.start(); 
    t2.start(); 
} 

的版本,但实现取决于porpose。 您应该只对不可变或线程安全的类使用AtomicReference。

在其他情况下,您可以使用不同的锁,易失性字段,不同的原子实现(如AtomicLong)或同步。

但是你应该记住一个比锁和一个锁更快的原子比同步更快。

+0

我想知道为什么我没有得到任何异常,当我运行此代码。 – LPD 2015-02-23 10:54:13

+1

您不会在您的代码中发现任何异常,因为引用下的操作通常是CPU架构(例如x86)的原子操作。但是如果你在异国情调的CPU上运行你的代码,你可能会得到异常。 – SergSW 2015-02-23 11:06:02

实际上,变量jai依次引用许多对象。在第二个线程的循环的每次迭代中,都会创建一个新对象并将其分配给该变量。所以,在jai上同步将无济于事。

如果你想确保由t2线程创建的所有对象由t1处理,你需要或者锁T1,等待t2创建对象或使用一种队列。阅读关于java.util.concurrent.BlockingQueue

更一般地,这是Producer-Consumer问题的一个例子。