public class TicketThread extends Thread {
   private volatile int i = 5;
   //我的理解是它是多个线程来共享它,不存在拷贝,修改以后必须马上写回。
   public void run(){
      while(i>0){ 
         i--;
         System.out.println(Thread.currentThread().getName()+"卖出车票,车票还剩 "+i+" 张");
         try {
            sleep(1000);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }      
   }
   
   
   public static void main(String[] args) {
      TicketThread t1 = new TicketThread();
      TicketThread t2 = new TicketThread();
      t1.setName("1号窗口");
      t2.setName("2号窗口");
      t1.start();
      t2.start();      
   }
}

解决方案 »

  1.   

    挥发变量.
    volatile修饰符告诉编译器被volatile修饰的变量可以被程序的其他部分改变。
    在多线程程序中,有时两个或更多的线程共享一个相同的实例变量。
    一般的变量在多线程中是有copy的,每个线程一个copy.
    volatile也不是很可靠
      

  2.   

    楼上的理解,好象反了吧。
    volantile自始至终只有一份拷贝吧。
      

  3.   


    楼主理解错误。
    精确讲述 volatile作用,还真是要Gosling那个书中的严格叙述方式。我作一个不是很精确的说法:即volatile的变量告诉编译器,该变量可能某种方式(如:多线程)发生改变,因而不能对其作某些假设性的代码安排代码优化,其结果是:编译器可确保在多线程下,对该变量的读操作或写操作是原子的。楼主的例子是不正确的。因为:i--不是原子操作(它包含了三种操作:读操作,减运算,写操作)因此:只是把i定义为volatile是没有用的。还是会出现错误。
      

  4.   

     volatile,英文释义: 挥发性的,可变的,不稳定的。以我原来的理解是多线程共享到此变量时,必须强制写回程度,而不是从缓存中读取,这样保证这个字段的同步性。       事实上不是这样的。在执行期间,编译好的代码出于效率原因会缓存字段值。由于可能有多条线程访问同一个字段,因此在读写字段、取值时不允许这里的缓存机制导致不一致性是很重要的。利用volatile修饰符可以告诉编译器,让它不要试图对本字段进行优化,因为这样会使得多条线程访问该字段时出现不可预测的结果。
    这段话,我还是不能很好的理解。
      

  5.   

    C里面也有,JAVA的什么意思我一直不明白,但是目前看来可能跟C的不一样。因为C中间插入汇编的话可能会修改某个变量,而由于编译器的优化,可能会忽略掉这个修改。要关闭这种所谓的优化,就需要对那个变量用violate申明
      

  6.   

    所谓的“缓存机制”就是读操作(如:使用变量的值)与写操作(如:v=12)的整个序列(如:Gosling那个书中的那个缓存操作序列)是逻辑上的原子操作保证读的数据一定是写的数据的最新版本
      

  7.   

    volatile 保证 各线程间共享数据的一致性,和数据操作的原子性,不能保证线程间同步。 能保证 i++ 的原子性,但是不能保证 i<0  i++ 和
    System.out.println(Thread.currentThread().getName()+"卖出车票,车票还剩 "+i+" 张");三个操作使用的是同一个 i。
    楼主除了 volatile , 还要使用同步关键字。
      

  8.   

    加了volatile 表示是线程安全的。
      

  9.   

    大哥们,请听小弟的理解:
    我以为加volantile时。
    假如上述程序,就是i在线程里没有另外的拷贝产生。
    只有一个共享的i.这才说明线程安全。
      

  10.   

    冒似我的理解跟楼主的一样,运行下结果才知道不是那样的关于write volatile和 read  volatile 还有什么原子性,期待高手详细的解答,最好就是举例说下
      

  11.   

    我想了半天,把以前的代码拿出来看了又看,才发现了楼主一个重要的问题,所以达不到你的预期效果
    并不是volatile用错了,而是你创建了两个单独的对象,两个单独的变量,怎么你也达不到共享的效果撒,如果你要达到同步,应该在同一个对象在不同的线程中掉用才对你这样修改一下
     TicketThread t1 = new TicketThread();
     Thread t11=new Thread(t1,"1号窗口");
     Thread t22=new Thread(t1,"2号窗口");
          t11.start();
          t22.start();    
    这样就能够达到同步了
      

  12.   

    volatile 这个关键字是保证定义的变量在内存块中只有一份,可以在不同线程间共享,只要有一个线程修改了该变量则所有的线程中的值都是一样的,保证了操作的原子性,但是如果使用不当会发生错误,
    1.volatile类型的变量不能依赖上一个结果,比如:int n =0;n=n++;这样就是依赖性的,这样的操作会造成volatile失效。
    2.在volatile操作的时候如果有依赖性操作,必须放到同步块中,比如: 
        public synchronized plus(){
           n = n++;
         }
       这样就能保证了原子的操作。