解决方案 »

  1.   

    我想作者的意思应该是,因为list本身是public的,所以你在这个方法上对类加锁而不对list加锁,那么这个对象还是可以被别的线程所操作。强调的一点是,所有的锁要加在同一个对象上,比如你要操作list,那么就都对list加锁,这样就可以保证安全了。当然这个例子里还有其他的线程安全问题,我这里说的保证安全是保证不被多个线程同时操作
      

  2.   

    如果 list 成员是公有的,则无法保证真正锁,因为调用者可以直接得到 list 的引用,然后改变它内部元素synchronized 并不能保证一段语句是原子操作,而是保证进入语句块之前,必须要先得到锁,如果得不到锁就必须等待别的线程释放锁
      

  3.   

    因为4-15使用的是对象内置锁,即锁住了list集合了
    又因为对象内置锁是互相排斥的
    所以当一个线程操作list的时候
    其他线程就不能操作list了
    4-14是的锁是加载方法上的,这个锁对于这个方法来说是同步的,其他线程不可以访问这个方法
    但是假如这个对象ListHelper 内还有其他普通方法(这些普通方法没有加锁) 这些方法也对list进行了增删,
    而其他线程恰好执行这些方法时 那么相对于list来说他就不是同步的了
    (因为list它本身就没有上对象内置锁 ,不会出现互斥)
      

  4.   

    请问是不是同步代码块有两层语义,比如在同步代码块synchronized(list){}中,
    1.同一时刻只有一个线程可以执行里面的代码
    2.某个线程执行里面的代码时,其他线程无法修改list
      

  5.   

    请问是不是同步代码块有两层语义,比如在同步代码块synchronized(list){}中,
    1.同一时刻只有一个线程可以执行里面的代码
    2.某个线程执行里面的代码时,其他线程无法修改list你不要这样理解锁,你要把锁理解为一种信号,一次性只能有一个线程获取,所以:
    1. 同一个时刻同一把锁只能由一个线程获取,所以被锁住的部分只能一个线程执行
    2. 如同我的分析,如果所有的线程都尝试去对 list加锁,那么同一个时刻必然只有一个线程可以获取到list上的锁,从而可以做相关的操作
      

  6.   

    锁是用来保护某个对象的,锁加在方法上,保护的是当前对象this,实际上锁应该保护list集合,所以应该加在list上。
      

  7.   

    第一个是方法锁,保证方法的线程安全,但是此时list可能被其他方法进行增删查改,就导致list内容乱掉,就没有任何安全的意义了。
    第二个是对象锁,保证list是线程安全,虽然此方法可以被多个线程同时访问,但是list对象只能允许一个线程去做修改 。
      

  8.   

    2楼讲得有道理。
    这个问题应该把ListHelper想成一个单例singleton的环境中,多个线程访问它。“如果有10个ListHelper对象",每线程一个,就都是线程安全的,没考虑的必要了,因为ListHelper.list成员又不是static.
    4-14不安全的反例:/*线程1*/
    boolean absent = !list.contains("X");
    // 此时发生时间片轮转,假如转到线程2执行
    Thread.sleep(100);
    if(absent) list.add("X");/*线程2*/
    var list = listHelper.list;
    list.add("X");
    //结果list中两个"X".这个例子总结起来就一句话:要使用相同的锁。你这话是对的。