public partial class Form1 : Form
    {        Thread thread = null;
        Thread th = null;
        public Form1()
        {
            InitializeComponent();
            thread = new Thread(time);
            th = new Thread(show);            thread.IsBackground = true;
            thread.Start();
            th.Start();
        }        int i = 0;
        ArrayList arr = new ArrayList ();
        public void time()
        {            while (true)
            {
                Thread.Sleep(100);
                i += 5;
                arr.Add(i);
                label1.Text = i.ToString();
            }        }        public void show()
        {
            while (true)
            {
                Thread.Sleep(100);         
                if (arr.Count != 0)
                {
                    int j = (int)arr[0];
                    label3.Text = j.ToString();
                    arr.RemoveAt(0);
                }
                label2.Text = i.ToString();
            }
        } 
    }
这里 需要对 time类中的 arr 加lock吗?我感觉 加不加 效果都一样。  并不会出现下面所说的情况,这个是什么原因呢??网上资料说“在多线程的程序中经常会遇到,多个线程要对一个对象进行操作的情况这样的话如果没有一个线程的控制的话一定会造成数据的损坏。比如两个现成要对同一个数组进行操作一个需要对数组进行加操作而另一个则要进行减操作。在这种情况下如果没有lock那就会很容易的出现超出数组界限的事情。”
 

解决方案 »

  1.   

    你Sleep(100),比lock的开销大得太多了...冲突几率自然低的很不容易发生...
      

  2.   

    本帖最后由 caozhy 于 2011-04-03 19:12:57 编辑
      

  3.   


    那我去掉  Sleep(100)是不是  就要 使用  lock了呢??
      

  4.   


    我也在考虑程序的正确性,可是我不知道 什么样的才是规范的~那就是说需要加  lock ?
      

  5.   

    2楼不是说了吗,一定要线程同步...不用lock就得用其他方法,比如Monitor、Mutex、同步事件等...不同步出问题是必然的,你现在看不到以后会看到,那时就晚了...
      

  6.   

    lock的用法上msdn/google上查查就知道了。
    lock(arr)
    {
      arr.Add(...);

    或者用 ArrayList.Synchronized 把你的ArrayList包装成线程同步的集合~
      

  7.   


    恩恩, 还有个问题就是  lock(arr),之后,其他线程就不能对 arr进行数据操作了呢??看了好多遍 lock还是不明白这个……我实验的结果:其它线程还是可以对 arr进行操作的。求解
      

  8.   

    lock不是说不能对它操作,而是让所有线程在这里排队,变成同步操作。让他们实际操作的数据不会因为同时处理而出错。举个很典型的例子:银行取款,你的账户里有100块钱:private int _money = 100;private void GetMoney(int money)
    {
       if (_money >= money)
           _money -= money;
    }
    现在是没有同步的,如果有两个线程,就像有两个人同时取款100元。
    那么结果如何?两个人都可以取出100元!银行破产了!那么同步的代码:
    private object _lockObj = new Object();
    private void GetMoney(int money)
    {
        lock(_lockObj)
        {
           if (_money >= money)
              _money -= money;
        }
    }
    因为这里同步了,所以_money不可能同时被两个线程做减法操作,一定是一个减完,另一个再减。
    这样判断上就不会出错了,因为第二个进来的线程判断_money已经小于money了。
      

  9.   

    就你这个程序来说是不需要加锁的.原因如下你在2个线程中对arr分别进行了添加和移除操作
    但是每个线程执行的操作是唯一的,不重复的
    也就是说,一个线程,只管添加,一个线程只管移除
    这2个操作本身并不存在冲突假设2个线程同时添加和删除,程序不会抛出异常,所以就这个程序来说不需要加锁
    如果有2个线程都在执行删除操作
    这时,如果arr只有1个对象
    而2个线程都在执行
    arr.RemoveAt(0);只有一个会成功,而另一个线程就抛出异常了
      

  10.   

    恩恩, 还有个问题就是 lock(arr),之后,其他线程就不能对 arr进行数据操作了呢??看了好多遍 lock还是不明白这个……我实验的结果:其它线程还是可以对 arr进行操作的。--------这个问题是这样的当一个线程进入
    lock(arr)
    {}
    的代码块之后第二个线程如果碰到 lock(arr),则会阻塞(暂停)不进入{}中
    直到第一个线程走出lock(arr){}之后,第二个线程才会进入{}中运行
      

  11.   

    比如两个现成要对同一个数组进行操作一个需要对数组进行加操作而另一个则要进行减操作。在这种情况下如果没有lock那就会很容易的出现超出数组界限的事情。”------------------------这种说话是不准确的,原因在12罗说了,如果只有一个线程进行remove操作
    并且在操作前判断了数组长度必须大于0,这个时候是不会出现数组越界的问题的
    至少不会出现下标越界
    有可能添加操作的线程没有进行上标判断而出现上标越界
      

  12.   

    别不懂装懂误导新人...删除操作时如果恰好arr空了,一定会抛索引越界异常...千万不要想当然地认为2个线程是交替执行,arr总不为空...线程的执行顺序是无法预测的,更无法保证...你和楼主都有一个误区,千万不要用你们的肉眼去看,用错误的逻辑和错误的测试去验证错误的想法...计算机的执行速度远比你们想象的快,线程调度也远比你们想象的复杂...
      

  13.   


    呵呵,没事,我刚才的话只就这个程序来说的
    因为原理LS几位朋友都已经解释的很清楚了,我没有再说我个人比较倾向,理论和实践结合的论述方式
    这样可以使LZ更加容易理解当时作为初级程序员来说必须先有"线程同步"的想法
    等完全理解后,
    如果可以判断代码绝对不会出现异常的时候,少一些lock也可以加快一些效率不是吗?就好比unsafe { }代码块,明知道是不安全的,为了效率还是会用到,呵呵~~~~
      

  14.   

    不锁的话连Count都会是错的,因为一个线程在size++,一个在size--,导致Count不能真实地反映size。同时索引0处的删除操作会把数组重新拷贝一次,发生其他错误的几率更大。
    这个东西没必要取巧,规规矩矩lock就是了,能以逻辑判断的情况下,比反复试错要更精确,反复测试这种方法不适用于和概率有关的问题。
    如果要采取更快速的锁机制,干脆就不用arraylist,自定义一个数组,对写和读的当前索引进行原子操作可以稍微提高速度,同时编程难度也增加了很多。
      

  15.   


    这个我以前没有考虑过,我一直以为.net的数组都是有默认线程同步的处理的...因为一直没有出错过
    也就没有深究了,下次可以reflector反编译后看一下...
      

  16.   

    这个我就不太明白这个...希望指教static int i = 0;public static void aaa()
    {
        for (int i = 0; i < 100; i++)
        {
            i++;
        }
    }public static void bbb()
    {
        for (int i = 0; i < 100; i++)
        {
            i--;
        }
    }
    [STAThread]
    static void Main()
    {    Thread t1 = new Thread(aaa);
        Thread t2 = new Thread(aaa);
        Thread t3 = new Thread(bbb);
        Thread t4 = new Thread(bbb);
        t1.Start();
        t2.Start();
        t3.Start();
        t4.Start();    while (t1.IsAlive
            && t2.IsAlive
            && t3.IsAlive
            && t4.IsAlive)
        {
            Thread.Sleep(100);
            Application.DoEvents();
        }
    }
            这样的操作会不会出错呢??
    我以前的理解一直就是,.net默认做了同步的处理......
      

  17.   


    确实会出问题    for (int i = 0; i < 100; i++)
        {
            Thread t1 = new Thread(aaa);
            Thread t2 = new Thread(bbb);
            t1.Start();
            t2.Start();
        }
    在如此极限的情况了200次...终于出问题了..ii=1..总算了却了一件心事...
      

  18.   


        for (int i = 0; i < 1000; i++)
        {
            new Thread(aaa).Start();
            new Thread(aaa).Start();
            new Thread(aaa).Start();
            new Thread(bbb).Start();
            new Thread(aaa).Start();
            new Thread(bbb).Start();
            
            new Thread(bbb).Start();
            new Thread(bbb).Start();
        }
    哈哈哈哈哈哈哈哈哈啊哈哈哈哈哈哈哈
    我疯啦....终于每次都出问题了!!!!
      

  19.   

    ls的,你是怎么打印ii的值的?在哪里打印的ii的值?你在打印前如果sleep足够长的时间,ii的值怎么会不等于0呢
      

  20.   


    不sleep 全部线程结束后打印ii