Synchronized关键字可以用来修饰4种不同类型的代码块: 实例方法
静态方法
实例方法中的代码块
静态方法中的代码块
同步方法 public synchronized void add(int value){
this.count += value;
}
注意到此处的Synchronized关键字是加在方法声明处,这会告诉JVM,它是一个同步方法。
实例同步方法的锁,是加在拥有该方法的对象之上。因此每个实例的Synchronized关键字实际上都加在了不同的方法之上。同时只有一个线程能执行该实例的同步方法。
同步静态方法 public static synchronized void add(int value){
count += value;
}
上面是一个同步静态方法。同步静态方法的锁是加在类之上的,而相同的类在JVM中只有一个,一个类中只能有一个线程正在运行,不论它调用的是哪个静态方法。
同步实例代码块 public void add(int value){
synchronized(this){
this.count += value;
}
}
上面是一个非同步方法中的同步实例代码块。注意到同步代码块中Synchronized(this)中的this意味着当前实例对象。括号中的对象被称为监控对象。
监控对象中只有一个线程能运行,下面的两个方法都把锁加在了当前的对象上,因此两者是等效的。线程每次只能执行其中的一个方法。如果第二个同步代码块把Synchronized加在不同的对象上,则这两个方法有可能被两个线程同时执行。 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);
}
}
}
静态方法中的同步代码
下面的两个方法,都把锁加在类上。 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同步的例子
下面的这个例子,开启了两个线程,并且对同一个counter对象调用了add方法。每次只有一个线程能调用同一个实例的add方法,因为此处的Synchronized修饰的是对象。 // 柜员类
public class Counter{
long count = 0;
// 此处有synchronized关键词修饰此实例方法
public synchronized void add(long value){
this.count += value;
}
}
// 顾客类
public class CounterThread extends Thread{
protected Counter counter = null;
public CounterThread(Counter counter){
this.counter = counter;
}
public void run() {
for(int i=0; i<10; i++){
counter.add(i);
}
}
}
// 运行类
public class Example {
public static void main(String[] args){
// 同一个counter实例
Counter counter = new Counter();
Thread threadA = new CounterThread(counter);
Thread threadB = new CounterThread(counter);
threadA.start();
threadB.start();
}
}