关于Java的synchronized使用问题

public class SynchronizedExcercises {

public static void main(String[] args) {
    // TODO Auto-generated method stub
    MyRunnabe myRunnabe = new MyRunnabe();
    Thread thread1 = new Thread(myRunnabe);
    thread1.start();
    myRunnabe.method2();
}

}

public class MyRunnabe implements Runnable {

private int b = 0;

@Override
public void run() {
    // TODO Auto-generated method stub
    method1();
}

public synchronized void method1() {
    this.b = 100;
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println("b = " + this.b + this.toString());
}

public void method2() {
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    this.b = 500;
    System.out.println("b = " + this.b);
}

}

这个计算结果为什么得出的结果是:
500
500

我的思路:method1()方法属于synchronized方法,会锁定MyRunnabe的监视器,这个时候虽然其中调用了sleep(5000),但是此时执行method2()方法法时会因为this.b被锁定而阻塞,应该是等method1()执行完了再执行this.b = 500这条语句,其计算结果应该为:
100
500

求解!

不是啊,如果你都执行的是第一个方法,他会排队,你现在是分别执行了两个不同的方法,他俩没有同步关系

你同步锁的是方法,不是对象,只是有线程method1没有执行完,其他线程进不去这个方法。这个方法内用到的变量和这个锁没关系,其他方法照样能够使用。

synchronized同步的是单个方法,多个线程都执行这个方法,会同步,如果执行的不是同一个方法,这个 synchronized就不行了,你需要通过锁定一个全局对象去同步,或者其他方式

**synchronized共有两种使用方法。

(1)一个类的实例方法 或 类方法上 加synchronize。

---如果是实例方法,那么就会对该实例对象本身加锁。任何其它线程,就无法在访问本synchronized方法 或者 其它synchronized方法。

但是,非synchronized方法,线程是能够继续访问的,没有什么锁的概念。

待本线程的synchronized方法执行完毕后,会释放对此实例的锁。其它线程,会公平竞争,谁先进入synchronized方法,谁就会获取了实例对象的锁。
---如果是类方法,则是对整个类加锁。原理和实例差不多。

(2)在方法内部,对类实例变量 或者 静态变量进行加锁。
----此时,其它线程在访问该实例变量 或者静态变量时,必须等待 实例或者类变量的锁 被释放后,才能继续往下执行。
----前提条件是,其它线程进入的方法内部,必须对 实例变量和静态变量 加synchronized快,否则,还是会继续执行的。

method1()方法属于synchronized方法,会锁定MyRunnabe的监视器,但是main方法所在的线程调用的method2方法并不需要监视器,main线程休眠2秒后将b设置成500后,Thread1线程休眠5秒后读取到的b也就是500了。
synchronize锁定的并不是this.b,而是this对象的监听器,它的锁定的意思是:此时Thread1线程拥有this锁,其他线程就无法获取this锁了,但是其他线程还是可以操作this这个变量的。
对象的锁和对象本身不是同一个东西,method2方法没有同步,所以它不需要获取锁,所以仍然能够操作this变量。

synchronized放在方法前面同步的是方法,表示任意时刻只能有一个线程能进入该方法。lz写的例子有问题,如果想测试,可以这样。
创建两个不同的线程类,他们共同拥有一个对象,在run方法内,把这个变量进行同步,如synchronized(var){}。就可以测试了

可以这么说把,你是想线程同步method1 ,但没有线程和你同步,m2 可以直接使用啊。
你用的 b 不是线程同步的,你在进入m1时 是 b=100,可是在sleep 5秒时 会执行m2,这样 b 就会赋值为500,
你在调用 b 肯定是 500 了。
就像:
b = 100;
do sth……
b = 500;
你觉得 b =?

在哪里加锁就会锁什么,夹在方法上锁方法,加在类上锁类

这不是很合理的设计吗

public class SynchronizedExcercises {

public static void main(String[] args) {
// TODO Auto-generated method stub
MyRunnabe myRunnabe = new MyRunnabe();
Thread thread1 = new Thread(myRunnabe);
thread1.start();
myRunnabe.method2();
}
从线程start()开始,调用线程的run()方法
public void run() {
// TODO Auto-generated method stub
method1();
} 然后进入method1()方法
public synchronized void method1() {
this.b = 100;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("b = " + this.b + this.toString());
}
mothod1()为线程安全方法,b =100, 进入sleep等待5秒, sleep 方法不释放锁,
此时 myRunnabe.method2(); 为main线程里的命令,它开始也执行,
public void method2() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.b = 500;
System.out.println("b = " + this.b);
}
它等待2秒,然后b = 500, 打印出来 ,这就是第一个500
当myRunnabe.method2(); 执行完后,method1()方法开始苏醒,
执行以下语句
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("b = " + this.b + this.toString());
}
】而此时的b已被method2()方法改为500,因为它是全局变量,从定义开始到类结束才结束
所以把method1()里面的b也改为500
,此时再打印一个500
所以造成的结果为
500
500
希望对您有帮助 谢谢

补充

public synchronized void method1() {
this.b = 100;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("b = " + this.b + this.toString());
}

它锁的是这个method1()方法 ,而不是这个类 ,所以可以执行myRunnabe.method2();
这条命令, 我的理解 谢谢

线程启动后 执行 method1 b = 100 , 休眠5S 于此同时 method2也会执行 休眠 2s b = 500 俩个方法输出 都是 500

也有可能输出 俩个 100 不过 几乎不可能