Java中的Synchronized关键字
可以用来修饰同步方法:
像这样synchronized void f() {/*body*/}
也可以修饰同步语句块:
像这样synchronized(object){/*body*/}。
其中修饰同步方法还可以分为修饰static方法和实例方法。
其中修饰同步语句块还可以分为修饰instance变量,Object Reference对象引用,class 字面常量。
当synchronized作用在方法上时,锁住的便是对象实例(this);
所以synchronized void f() {/*body*/}和 void f(synchronized(this){/*body*/})是等价的。
当作用在静态方法时锁住的便是对象对应的Class实例,因为Class数据存在于永久带,因此静态方法锁相当于该类的一个全局锁;
当synchronized作用于某一个对象实例时,锁住的便是对应的代码块。
在HotSpot JVM实现中,锁有个专门的名字:对象监视器。
synchronized(class)
synchronized(this)
->线程各自获取monitor,不会有等待.
线程分别获取class和this,不会造成等待的例子:
package com.hyy.test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SyncTest02 implements Runnable { private static boolean flag = true; private void testSync1() { synchronized (this) { for (int i = 0; i < 100; i++) { System.out.println("testSyncObject: " + i); } } } private void testSync2() { synchronized (SyncTest02.class) { for (int i = 0; i < 100; i++) { System.out.println("testSyncClass:" + i); } } } @Override public void run() { // TODO Auto-generated method stub if (flag) { flag = false; testSync1(); } else { flag = true; testSync2(); } } public static void main(String[] args) { ExecutorService exec = Executors.newFixedThreadPool(2); SyncTest02 sy1 = new SyncTest02(); SyncTest02 sy2 = new SyncTest02(); exec.execute(sy1); exec.execute(sy2); exec.shutdown(); } }
synchronized(this)
synchronized(this)
->如果不同线程监视同一个实例对象,就会等待,如果不同的实例,不会等待.
不同线程监视同一个实例对象的例子:
package com.hyy.test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SyncTest { public static void main(String[] args) { ExecutorService es = Executors.newFixedThreadPool(2); MyCount mc = new MyCount(); MyThread mt1 = new MyThread(mc, "thread 1"); MyThread mt2 = new MyThread(mc, "thread 2"); es.execute(mt1); es.execute(mt2); es.shutdown(); } } class MyThread extends Thread { MyCount count; String threadName; public MyThread(MyCount count, String threadName) { // TODO Auto-generated constructor stub this.count = count; this.threadName = threadName; } @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < 10; i++) { count.addOne(threadName); try { sleep(100L); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } class MyCount { int i; public void addOne(String threadName) { synchronized (this) { i++; System.out.println(threadName + ":" + i); } } }
输出为
thread 1:1 thread 2:2 thread 1:3 thread 2:4 thread 2:5 thread 1:6 thread 2:7 thread 1:8 thread 1:9 thread 2:10 thread 1:11 thread 2:12 thread 2:13 thread 1:14 thread 1:15 thread 2:16 thread 1:17 thread 2:18 thread 1:19 thread 2:20
从输出上看,线程间出现了等待
不同线程监视不同实例对象的例子:
package com.hyy.test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SyncTest { public static void main(String[] args) { ExecutorService es = Executors.newFixedThreadPool(2); MyCount mc = new MyCount("countONE"); MyCount mc2 = new MyCount("countTWO"); MyThread mt1 = new MyThread(mc, "thread 1"); MyThread mt2 = new MyThread(mc2, "thread 2"); es.execute(mt1); es.execute(mt2); es.shutdown(); } } class MyThread extends Thread { MyCount count; String threadName; public MyThread(MyCount count, String threadName) { // TODO Auto-generated constructor stub this.count = count; this.threadName = threadName; } @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < 10; i++) { count.addOne(threadName); try { sleep(100L); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } class MyCount { int i; String countName; public MyCount(String countName) { // TODO Auto-generated constructor stub this.countName = countName; } public void addOne(String threadName) { synchronized (this) { i++; System.out.println(threadName +"&&"+countName+ ":" + i); } } }
输出为
thread 2&&countTWO:1 thread 1&&countONE:1 thread 2&&countTWO:2 thread 1&&countONE:2 thread 2&&countTWO:3 thread 1&&countONE:3 thread 2&&countTWO:4 thread 1&&countONE:4 thread 1&&countONE:5 thread 2&&countTWO:5 thread 2&&countTWO:6 thread 1&&countONE:6 thread 2&&countTWO:7 thread 1&&countONE:7 thread 1&&countONE:8 thread 2&&countTWO:8 thread 2&&countTWO:9 thread 1&&countONE:9 thread 1&&countONE:10 thread 2&&countTWO:10
从输出上看,线程间没有发上等待。
synchronized(class)
synchronized(class)
->如果不同线程监视同一个实例或者不同的实例对象,都会等待.
不同线程监视不同实例对象的例子:
package com.hyy.test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SyncTest02 implements Runnable { private static boolean flag = true; private void testSync1() { synchronized (SyncTest02.class) { for (int i = 0; i < 100; i++) { System.out.println("testSyncObject: " + i); } } } private void testSync2() { synchronized (SyncTest02.class) { for (int i = 0; i < 100; i++) { System.out.println("testSyncClass:" + i); } } } @Override public void run() { // TODO Auto-generated method stub if (flag) { flag = false; testSync1(); } else { flag = true; testSync2(); } } public static void main(String[] args) { ExecutorService exec = Executors.newFixedThreadPool(2); SyncTest02 sy1 = new SyncTest02(); SyncTest02 sy2 = new SyncTest02(); exec.execute(sy1); exec.execute(sy2); exec.shutdown(); } }