public class SynchronizedTest implements Runnable
{
private Integer i = new Integer(1); public  void a(){
synchronized(i){
i = new Integer(2);
try{
Thread.sleep(5000);
}catch (Exception e){

}
System.out.println("a() i = "+i);
}
} public void b(){
System.out.println("b() i ="+ i);
} public void setI(Integer i){
this.i = i;
} public void run(){
a();
System.out.println("a()---------------");
} public static void main(String[] args){
SynchronizedTest st = new SynchronizedTest(); Thread t = new Thread(st);
t.start();
try{
Thread.sleep(1000);
}catch(Exception e){}

st.b();
st.setI(5);
}
}
/*
*为什么输出结果是
*b() i = 2
*a() i = 5
*a()--------------
*为什么是这样的结果,synchronized(i)不是已经把 i 锁住了吗?怎么还可以修改 i 的值呀?
*/

解决方案 »

  1.   

    锁住?
    锁住 就不会释放了吗????
    楼主。先执行 st.b(); 然后 线程醒了 运行 run方法里面的函数 就ok了
      

  2.   

    单线程哪有锁的问题,根本就不会发生死锁的问题,至于修改i的值,很正常,为什么不可以修改啊?synchronized(i)只是同步,并不是不能修改i的值。
      

  3.   

    帮你顶下啊 想不明白是什么时候释放的锁 刚才试了下应该是sleep醒了之后就释放了 不知道啥原因
      

  4.   


    <p><textarea cols="50" rows="15" name="code" class="java">public class SynchronizedTest implements Runnable {
    private Integer i = new Integer(1);
    public void a(Integer i) {
    synchronized (i) {
    i = new Integer(2);
    try {
    Thread.sleep(5000);
    } catch (Exception e) {
    }
    System.out.println("a() i = " + i);
    }
    }
    public void b() {
    System.out.println("b() i =" + i);
    }
    public void setI(Integer i) {
    this.i = i;
    }
    public void run() {
    a(i);
    System.out.println("a()---------------");
    }
    public static void main(String[] args) {
    SynchronizedTest st = new SynchronizedTest();
    Thread t = new Thread(st);
    t.start();
    try {
    Thread.sleep(1000);
    } catch (Exception e) {
    }
    st.b();
    st.setI(5);
    }
    }</textarea>&nbsp;</p>
      

  5.   

    我的意思是 synchronized(i) 不是已经把 i 锁住了吗?锁还没有释放前怎么执行 setI() 方法能成功,不是在解锁以前不能修改 i 的值吗?。
    程序应该有两个线程吧,一个 main 线程 一个SynchronizedTest类的线程吗?
      

  6.   

    Thread.sleep(5000);  这个线程睡觉的时候锁就释放了..
      

  7.   

    你锁的不是i 是i所属的那个对象 你把i 换成SynchronizedTest.class 或者this 都是一个效果 想我上面写的 锁的才是i
      

  8.   

    我测试过了,有两点
    1 你的setI中并没有synchronized 
    2 即使加了synchronized ,也没用,和这个integer类型有关.换成String就成功了
      估计应该是integer和int在jdk中已经自动转换了
      

  9.   

    public void setI(Integer i) {
    this.i = i;
    }这个方法中也加上synchronized (i) 
    public void setI(Integer i) {
    synchronized (i) {
    this.i = i;
    }
    }这样就可以了
      

  10.   


    public class SynchronizedTest implements Runnable {
    private Integer i = new Integer(1);
    private Integer other = new Integer(1); public void a() {
    synchronized (other) {
    i = new Integer(2);
    try {
    Thread.sleep(1000);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    System.out.println("a() i = " + i);
    }
    } public void b() {
    System.out.println("b() i =" + i);
    } public void setI(Integer num) {
    synchronized (other) {
    this.i = num;
    }
    } public void run() {
    a();
    System.out.println("a()---------------");
    } public static void main(String[] args) {
    SynchronizedTest st = new SynchronizedTest(); Thread t = new Thread(st);
    t.start();
    try {
    Thread.sleep(200);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    st.b();
    st.setI(5);
    }
    }上面的代码有点问题,经过一下以上的bug,测试通过,上面的有些兄弟好像没有理解你的意思 !这样改就可以了
    你说为什么可以修改i的值是因为i = new Integer(2);//这个时间监视器(对象锁)不一样了,还有就是你的
    public void setI(Integer i){
    this.i = i;
    }这个方法根本没有同步
      

  11.   

    你的代码里只有一个线程,synchronized只是表示多个线程同时进入你的a() 方法时,其中一个线程对i对象进行锁定,其他线程等待前一线程释放后才能进入a()方法i这个变量是你这个线程独享的,基本上不存在共享变量锁定的问题,而且i = new Integer(2);这样把原引用的Integer对象都丢失了,i新指向一个Integer对象了,还不清楚原来i指向的Integer对象是否还是会被锁定,有点乱了,这样测多线程的锁定是不行的,根本看不出来建议楼主不要把synchronized()中锁定的对象指定为本线程的私有变量,synchronized(ArrayList ls)这样每次传同一个ArrayList实例,就好看出哪个线程在锁定的情况了
      

  12.   

    在同步中Thread.sleep(1000);并不能释放锁,使用 wait() 方法时可以释放这个锁。谢谢大家。
      

  13.   

    多线程间的通信:package Thread;public class TwoThread {
        public static void main(String[] args) {
            Queue q=new Queue ();//new出一个q:后面的两个线程都是用的同一个q,保证一个put一个get
            Producer p=new Producer (q);//让new出的p去往q里面put
            Customer c=new Customer (q);//让new出的c从q中get
            p.start();//p和q开始的顺序并不报错
            c.start();
            
        }
    }
    class Producer extends Thread
    {
        Queue q;
        public Producer(Queue q) {
            this.q=q;//给成员变量赋值,再一调运q的put方法
        }
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                q.put(i);//此处只是让q去put  10次
                System.out.println("Producer put "+i);//并且输出本次放的是第几杯
            }
        }
    }
    class Customer extends Thread
    {
        Queue q;
        public Customer(Queue q) {
            this.q=q;//给成员变量赋值,再一调运q的get方法
        }
        @Override
        public void run() {
            while (true) {//死循环:只要q里面有,就去get
                //get方法有返回值,返回值就是producer所put的数量
                //此处也不需要去考虑是第几杯
                //在Queue中的value解决可这一问题:
                //put中的I赋给value,get方法有返回值就value的值
                System.out.println("Customer get "+q.get());
                //如果循环完了,就跳出循环,否则线程不会自己结束
                if (q.value==9) {
                    break;
                }
            }
            
        }
    }
    class Queue
    {
        int value;
        boolean bFull=false;
        public synchronized void put (int i)//在producer中的put方法中就是将其I传进来
        {
            if (!bFull) {//条件为真(如果没满,就倒水)
                value=i;//给value赋值,现在有几杯水
                bFull=true;//满了
                notify();//唤醒其他线程(让customer去get)
            }
            try {
                wait();//告诉customer去get后自己等待customer的get结束
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        public synchronized int get()
        {
            if (!bFull) {//如果没满就等待,如果满了就不进    **这就是为什么main里面谁先开始不报错的原因**
                //get和put方法中的if条件判断起到了至关重要的作用
                try {
                    wait();
                } catch (InterruptedException e) {
                    
                    e.printStackTrace();
                }
            }
            bFull =false;//赋值为没满
            notify();//唤醒producer去put
            return value;//get的返回值就是put的时候给value赋的值
        }
    }
      

  14.   

    修改下setI方法
    public void setI(Integer i){
    synchronized(i)
    {
    this.i = i;
    }
    }
      

  15.   

    虽然该贴已经结,虽然这是一年多以前的帖子,但我是我忍不住要回复一下,因我也遇到了类似的问题,我目前的理解是:java为每个对象都定义了一个锁对象,只能对对象加锁,对i加锁的意思是对i这个引用所指向的对象加锁——i本身不是对象,它只是引用,它保存的是new生成的对象的地址。楼主的run方法中为i重新分配了对象,这样一来,之前加锁的对象就无法访问了(之前加锁的对象就是在定义i时所new的对象,垃圾回收器要回收它,因为没有任何引用来指向它),而新产生的对象(new Integer(2))并没有被加锁。所以导致了问题。
    我只是不确定我的理解对不,如果哪个人看见了我的回复,请不吝赐教。