java 同步块(Java Synchronized Blocks)
Java 同步块包括方法同步和代码块同步。java 同步可以避免资源竞争,避免死锁。
主题包括的主要内容:
The Java synchronized Keyword
在java中,同步是用 synchronized
关键字代表的. 同步是针对对象和类来说的。一个对象上的所有同步块只能被一个线程锁住。其他所有的线程试图访问同步块的方法,都要等到占用资源的线程释放了才能访问。
synchronized
关键字可以用到4个种场景:
- Instance methods
- Static methods
- Code blocks inside instance methods
- Code blocks inside static methods
Synchronized Instance Methods
Here is a synchronized instance method:
public synchronized void add(int value){ this.count += value; }
当一个方法上用到synchronized关键字,Java才能知道它是个同步方法。
一个实例同步方法只属于实例本身。每个实例都有自己的同步方法。
Synchronized Static Methods
Static methods are marked as synchronized just like instance methods using thesynchronized
keyword. Here is a Java synchronized static method example:
public static synchronized void add(int value){ count += value; }
同样 synchronized
告诉Java 这是一个同步方法。
同步静态方法属于类对象。在VM中只有一个类对象,因此只能有一个线程执行静态同步方法。
Synchronized Blocks in Instance Methods
有时候, 不需要同步整个方法,只需要同步方法里面的一部分,可以借助同步块来完成工作。
Here is a synchronized block of Java code inside an unsynchronized Java method:
public void add(int value){ synchronized(this){ this.count += value; } }
这个例子是用同步块标记一块同步代码。这个同步块代码就相当于同步方法。
Notice how the Java synchronized block construct takes an object in parentheses. In the example "this" is used, which is the instance the add method is called on. The object taken in the parentheses by the synchronized construct is called a monitor object. The code is said to be synchronized on the monitor object. A synchronized instance method uses the object it belongs to as monitor object.
对于同一个对象只能有一个线程访问同步块。
下面两个方法的代码,效果是一样的。
public class MyClass { public synchronized void log1(String msg1, String msg2){ log.writeln(msg1); log.writeln(msg2); } public void log2(String msg1, String msg2){ synchronized(this){ log.writeln(msg1); log.writeln(msg2); } } }
只能有一个线程执行(针对同一个对象) ;
第二个方法是不同的线程执行的时候会在同步块里面发生等待(针对同一对象)。
Synchronized Blocks in Static Methods
下面两个静态方法是在类对象上的:
public class MyClass { public static synchronized void log1(String msg1, String msg2){ log.writeln(msg1); log.writeln(msg2); } public static void log2(String msg1, String msg2){ synchronized(MyClass.class){ log.writeln(msg1); log.writeln(msg2); } } }
一个线程只能在同一时间执行上面的任何一个方法。
对于第二个方法:只能有一个线程在代码块里面执行。
Java Synchronized Example
public class MyClass { public static synchronized void log1(String msg1, String msg2){ try { TimeUnit.SECONDS.sleep(5) ; } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(msg1); System.out.println(msg2); } public static synchronized void log3(String msg1, String msg2){ System.out.println(msg1); System.out.println(msg2); } public static void log2(String msg1, String msg2){ synchronized(MyClass.class){ try { TimeUnit.SECONDS.sleep(3) ; } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(msg1); System.out.println(msg2); } } public static void log4(String msg1, String msg2){ synchronized(MyClass.class){ System.out.println(msg1); System.out.println(msg2); } } public void log5(String msg1, String msg2){ synchronized(this){ System.out.println(msg1); System.out.println(msg2); } } }
public class SynchronizedTest { Thread t1 = new Thread(new Runnable() { @Override public void run() { MyClass.log1("msg11", "msg12") ; } }) ; Thread t2 = new Thread(new Runnable() { @Override public void run() { MyClass.log2("msg21", "msg22") ; } }) ; Thread t3 = new Thread(new Runnable() { @Override public void run() { MyClass.log3("msg31", "msg32") ; } }) ; Thread t4 = new Thread(new Runnable() { @Override public void run() { MyClass.log4("msg41", "msg42") ; } }) ; Thread t5 = new Thread(new Runnable() { @Override public void run() { new MyClass().log5("msg51", "msg52") ; } }) ; public static void main(String[] args) { SynchronizedTest st = new SynchronizedTest() ; st.t1.start() ; // st.t3.start() ; // st.t2.start() ; // st.t4.start() ; st.t5.start() ; int i = 0 ; while(true){ try { TimeUnit.SECONDS.sleep(1) ; System.out.println("---------------> " + i); i ++ ; } catch (InterruptedException e) { e.printStackTrace(); } if(i > 10 ){ break ; } } } }
测试组合:
1. 测试实例方法组合;
2. 测试静态方法组合;
3. 测试实例方法和静态方法组合;(注意方法里面的 sleep, 是为了做到更好的测试效果)。