4种用法
1.方法声明
放在访问操作符(public等)之后,返回类型声明(void等)之前
public synchronized void synMethod() {}
一次只能有一个线程进入该方法,其他线程要想在此时调用该方法只能排队等候,只有当前线程执行完该方法后,别的线程才能进入.
2.代码块中
后跟括号, 括号里是变量
public int synMethod(int arg) {
synchronized(arg) { //一次只能有一个线程进入代码块执行 }
}
3.代码块中
后跟括号, 括号里是对象
线程获得的是对象锁,如果为了对对象使用部分锁,通常是虚拟对象来上锁(创建一个简单对象)
public void run() {
synchronized ( Ojbect instance ) {}
}
4.代码块中
后跟括号, 括号里是类名
线程获得的是类对象锁,线程对该类的静态方法和静态变量的等都不能操作
public class TestThread {
public void testSynch() { …….. synchronized( TestThread.class ) { ………. } }
}
示例分析
public class Test implements Runnable { int b = 100; public synchronized void m1() throws Exception { b = 1000; System.out.println("m1() Thread.sleep(5000) begin"); Thread.sleep(5000); System.out.println("m1() Thread.sleep(5000) end"); System.out.println("b=" + b); } public void m2() throws Exception { System.out.println("m2() Thread.sleep(2500) begin"); Thread.sleep(2500); System.out.println("m2() Thread.sleep(2500) end"); b = 2000; } public void run() { try { m1(); } catch (Exception e) { } } public static void main(String args[]) throws Exception { Test test = new Test(); Thread t = new Thread(test); t.start(); test.m2(); //Thread.sleep(1000); System.out.println(test.b); } }
当m2被synchronized修饰以后结果:
m2() Thread.sleep(2500) begin
m2() Thread.sleep(2500) end
2000
m1() Thread.sleep(5000) begin
m1() Thread.sleep(5000) end
b=1000
当m1和m2方法都设为synchronized了之后,把该类this变量作为同步锁的线程无法同时访问这两个方法,也就是说同时有且只有一个线程能访问其中任一个方法。这里有两个线程 Thread-t 和Thread-main:
<1>Thread-main 先进入了m2方法,沉睡2500毫秒之后, b被赋为2000 ,随后Thread-main离开了m2方法;
<2> Thread-main离开了m2方法之后,马上执行打印语句,打印出了b,b值为2000,然后Thread-main就释放了同步锁this;
<3>这时 Thread-t 就拿到同步锁,同时进入了m1方法,b随即被赋为1000,然后开始沉睡5000毫秒,该线程进入sleep状态;
<4> Thread-t 睡眠结束,进入打印语句,打印出了b,b值为1000。
当m2被synchronized修饰,并且在test.m2()后加上Thread.sleep(1000)以后结果:
m2() Thread.sleep(2500) begin
m2() Thread.sleep(2500) end
m1() Thread.sleep(5000) begin
1000
m1() Thread.sleep(5000) end
b=1000
<1>Thread-main先进入了m2方法,沉睡2500毫秒之后, b被赋为2000 ,随后Thread-main离开了m2方法;
<2>Thread-main离开了m2方法之后,开始沉睡1000毫秒,该线程进入sleep状态,释放了同步锁this;
<3> Thread-t 拿到同步锁,同时进入了m1方法,b随即被赋为1000,然后开始沉睡5000毫秒,该线程进入sleep状态;
<4>这时Thread-main正好沉睡完1000毫秒,进入执行打印语句段,打印出了b,b值为1000;
<5> Thread-t 睡眠结束,进入打印语句,打印出了b,b值为1000。