A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 田向向 高级黑马   /  2012-6-24 00:26  /  2355 人查看  /  2 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 田向向 于 2012-6-24 22:00 编辑

package txx;
public class Account {  
            private int balance;  
         
    public Account(int balance) {  
               this.balance = balance;  
            }  
        
            public int getBalance() {  
                return balance;  
            }  
        
           public void add(int num) {  
                balance = balance + num;  
            }  
         
            public void withdraw(int num) {  
                balance = balance - num;  
            }  
         
            public static void main(String[] args) throws InterruptedException {  
               Account account = new Account(1000);  
                Thread a = new Thread(new AddThread(account, 20), "add");  
               Thread b = new Thread(new WithdrawThread(account, 20), "withdraw");  
              a.start();  
                b.start();  
       a.join();  
               b.join();  
                System.out.println(account.getBalance());  
          }  
         
            static class AddThread implements Runnable {  
               Account account;  
                int     amount;  
        
               public AddThread(Account account, int amount) {  
                   this.account = account;  
                    this.amount = amount;  
               }  
         
                public void run() {  
                  for (int i = 0; i < 200000; i++) {  
                        account.add(amount);  
                    }  
      }  
            }  
         
           static class WithdrawThread implements Runnable {  
                Account account;  
                int     amount;  
         
                public WithdrawThread(Account account, int amount) {  
                    this.account = account;  
                    this.amount = amount;  
               }  
         
                public void run() {  
                   for (int i = 0; i < 100000; i++) {  
                       account.withdraw(amount);  
                   }  
                }  
           }  
        }  
第一次执行结果是2244600,第二次是3120220,第三次是2898720,我是菜鸟,求解释

2 个回复

倒序浏览
本帖最后由 周兴中 于 2012-6-24 03:34 编辑

由于你操作共享数据时没有进行同步处理,使得balance在被进行加减操作时,出现被多加或者多减的情况,当运行次数足够多时,很容易出现不一样的结果.
例如:
balance = balance + num;  假设此时 balance为1000,num为20  
在balance还没有被赋值时, 此时balance仍为1000,被b线程抢走了执行权.
执行了这句 balance = balance - num;   此时balance为980
然后当a线程再次拿到执行权时,它仍认为balance为1000,赋值后结果为1020 ,结果错误.

例2

public class MyThread extends Thread
{
    public static int n = 0;

    public void run()
    {
        int m = n;
        yield();
        m++;
        n = m;
    }
    public static void main(String[] args) throws Exception
    {
        MyThread myThread = new MyThread ();
        Thread threads[] = new Thread[100];
        for (int i = 0; i < threads.length; i++)
            threads = new Thread(myThread);
        for (int i = 0; i < threads.length; i++)
            threads.start();
        for (int i = 0; i < threads.length; i++)
            threads.join();
        System.out.println("n = " + MyThread.n);
    }
}
由于先调用了thread1的start方法,因此,thread1的run方法一般会先运行。当thread1的run方法运行到第一行(int m = n;)时,将n的值赋给m。当执行到第二行的yield方法后,thread1就会暂时停止执行,而当thread1暂停时,thread2获得了CPU资源后开始运行(之前thread2一直处于就绪状态),当thread2执行到第一行(int m = n;)时,由于thread1在执行到yield时n仍然是0,因此,thread2中的m获得的值也是0。这样就造成了thread1和thread2的m获得的都是0。在它们执行完yield方法后,都是从0开始加1,因此,无论谁先执行完,最后n的值都是1,只是这个n被thread1和thread2各赋了一遍值。这个过程如下图如示:


所以,当对共享数据进行写操作时,要进行数据同步,
数据同步就是指在同一时间,只能由一个线程来访问被同步的类变量,当前线程访问完这些变量后,其他线程才能继续访问。

你的代码要想得到正确的结果,可以简单的在add和 withdraw 方法前加 synchronized修饰. 即可同步

点评

谢谢  发表于 2012-6-24 22:01

评分

参与人数 2技术分 +2 黑马币 +1 收起 理由
田向向 + 1 赞一个!
职业规划-刘倩老师 + 2 赞一个!

查看全部评分

回复 使用道具 举报
两个线程没有同步而已,我修改了你的程序:
public class Account {  
    private int balance;  
    private Object obj;

public Account(int balance) {  
       this.balance = balance;  
       obj=new Object();//让对象初始化时获得一把锁
    }  

    public int getBalance() {  
        return balance;  
    }  
    public Object getObj(){
            return obj;
    }

   public void add(int num) {  
        balance = balance + num;  
    }  

    public void withdraw(int num) {  
        balance = balance - num;  
    }  
  
    public static void main(String[] args) throws InterruptedException {  
       Account account = new Account(1000);  
        Thread a = new Thread(new AddThread(account, 20), "add");  
       Thread b = new Thread(new WithdrawThread(account, 20), "withdraw");  
      a.start();  
        b.start();  
a.join();  
       b.join();  
        System.out.println(account.getBalance());  
  }  

    static class AddThread implements Runnable {  
       Account account;  
        int     amount;  

       public AddThread(Account account, int amount) {  
           this.account = account;  
            this.amount = amount;  
       }  
      
        public void run() {
                synchronized (account.obj) {//加入同步代码块,使线程安全
                                 for (int i = 0; i < 200000; i++) {  
                account.add(amount);  
            }  
                        }
         
}  
    }  
  
   static class WithdrawThread implements Runnable {  
        Account account;  
        int     amount;  

        public WithdrawThread(Account account, int amount) {  
            this.account = account;  
            this.amount = amount;  
       }  
  
        public void run() {  
                synchronized (account.obj) {//加入同步代码块,使线程安全
                                 for (int i = 0; i < 100000; i++) {  
               account.withdraw(amount);  
           }
                        }
        }  
   }  
}  

点评

谢谢  发表于 2012-6-24 22:01

评分

参与人数 1黑马币 +1 收起 理由
田向向 + 1 赞一个!

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马