所有对象都自动含有单一的锁,也就是所有对象都有且只有唯一的锁,所以当某个任务(线程)访问一个类A中含有sycnhronized的方法是,那么在这个线程从该方法返回之前(也就是该方法在当前线程执行完之前),类A中的其他被该关键字标记的方法在其他的线程中都会被阻塞。
通俗点说就是,当调用A的含有synchronized的方法是,A会被枷锁,此时A中其他含有synchronized方法只有等到前一个方法调用完毕释放了锁才能被调用
具体说明见另一篇博客<
下面看看具体的程序,其中,Timer中的字段num是共享资源
package com.bankht.synchronize;
public class TestSync implements Runnable {
Timer timer = new Timer();
public static void main(String[] args) {
TestSync test = new TestSync();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
public void run() {
timer.add(Thread.currentThread().getName());
}
}
class Timer {
private static int num = 0;
public void add(String name) {
num++;
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
System.out.println(name + ", 你是第" + num + "个使用timer的线程");
}
}
由于没有同步,所以运行结果如下所示
t1, 你是第2个使用timer的线程
t2, 你是第2个使用timer的线程
也就是说当线程一运行到num++的时候被打线程2打断了,由于java中递增和递减操作均不是原子操作,所以本程序中即使没有调用sleep,也会出现这种被打断的情况
下面看看同步的效果
public void add(String name) {
synchronized (this) {//同步
num++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println(name + ", 你是第" + num + "个使用timer的线程");
}
}
这样运行结果就会出是正确的
t1, 你是第1个使用timer的线程
t2, 你是第2个使用timer的线程
但是,下面为了说明问题把TestSync里面的run方法改成如下所示
public void run() {
/
time.add(Thread.currentThread().getName());
try {
Thread.sleep(1000);//为了显示结果,让其睡眠一秒
} catch (InterruptedException ex) {
Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(Thread.currentThread().getName() + "----");
}
那么在此运行就是
t1, 你是第1个使用timer的线程
t2, 你是第2个使用timer的线程
t1--------
t2--------
而不是你所想象的
t1, 你是第1个使用timer的线程
t1----
t2, 你是第2个使用timer的线程
t2----
原因就是在线程t1在睡眠的时候,线程t2切换进来,执行了一次,怎样得到正确的结果呢,下面把TestSync里面的run方法做如下改进就可以得到上面预期的结果
public void run() {
synchronized(time){
time.add(Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(Thread.currentThread().getName() + "----");
}
}
因为t1先获得time的锁,所以在执行完run里面的同步块之前,即使sleep(),t2也不会执行,因为t2没有获得time的锁,且sleep()操作也不释放锁(这也是和wait的巨大区别)
附录:TestSync.java全部代码
package com.bankht.synchronize;
import java.util.logging.Level;
import java.util.logging.Logger;
public class TestSync implements Runnable {
Timer timer = new Timer();
public static void main(String[] args) {
TestSync test = new TestSync();
Thread t1 = new Thread(test);
Thread t2 = new Thread(test);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
// public void run() {
// timer.add(Thread.currentThread().getName());
// }
// public void run() {
// timer.add(Thread.currentThread().getName());
// try {
// Thread.sleep(1000);//为了显示结果,让其睡眠一秒
// } catch (InterruptedException ex) {
// Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);
// }
// System.out.println(Thread.currentThread().getName() + "----");
// }
public void run() {
synchronized(timer){
timer.add(Thread.currentThread().getName());
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
Logger.getLogger(TestSync.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(Thread.currentThread().getName() + "----");
}
}
}
class Timer {
private static int num = 0;
// public void add(String name) {
//
// num++;
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// }
// System.out.println(name + ", 你是第" + num + "个使用timer的线程");
//
// }
public void add(String name) {
synchronized (this) {// 同步
num++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println(name + ", 你是第" + num + "个使用timer的线程");
}
}
}