这篇文章是根据 http://www.tianshouzhi.com/api/tutorials/mutithread/67做的一些测试总结:
java四种同步块:
1.实例方法同步
注意:注意:多个线程要运行的是同一个对象实例的同步方法,如果一个每个线程运行的是不同的对象实例的同步方法,是没有同步效果的,因为每个对象实例是把自身当成锁,就导致没有公用一个锁。
测试代码:
public class Two {
private int count = 0;
public synchronized void add(){
this.count++;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
// test
public static void main(String[] args) throws InterruptedException{
final Two t1 = new Two();
final Two t2 = new Two();
for(int i = 0; i < 10; i++){
new Thread(){
@Override
public void run() {
for(int j = 0; j < 100; j++){
t1.add();
t2.add();;
}
}
}.start();
}
Thread.sleep(10000);
System.out.println("t1.count = " + t1.count);
System.out.println("t2.count = " + t2.count);
}
}
测试结果:
t1.count = 1000
t2.count = 1000
如果我们把上面的 public synchronized void add改写成 public void add,那么测试结果为:
t1.count = 983
t2.count = 965
可以看到每个实例的add方法并不是线程安全的,那么如果我们把count这个变量改写成类变量(static int count = 0;)同时add方法加上synchronized关键字呢?
测试结果:
t1.count = 1934
t2.count = 1934
因为是类成员变量,所以实际上+的都是同一个变量。
2.静态方法同步
上面最后一个例子我们看到,将count声明为类成员变量,结果不是2000,而是1934。这是因为虽然count为类成员变量,但是add方法还是实例的同步方法,这就会造成线程不安全,这时我们可以将add方法声明为静态方法同步
测试代码:
public class Two {
static int count = 0;
public static synchronized void add(){
count++;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
// test
public static void main(String[] args) throws InterruptedException{
final Two t1 = new Two();
final Two t2 = new Two();
for(int i = 0; i < 10; i++){
new Thread(){
@Override
public void run() {
for(int j = 0; j < 100; j++){
t1.add();
t2.add();;
}
}
}.start();
}
Thread.sleep(10000);
System.out.println("t1.count = " + t1.count);
System.out.println("t2.count = " + t2.count);
}
}
测试结果:
t1.count = 2000
t2.count = 2000
理想,线程安全。因为生命了静态的同步块也就保证了只允许一个线程执行同一个类中的静态同步方法,即使你是这个类的多个实例。
3.实例方法中的同步块
测试代码:
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);
}
}
}
在上例中,每次只有一个线程能够在两个同步块中任意一个方法内执行。如果第二个同步块不是同步在this实例对象上,那么两个方法可以被线程同时执行。其实像public synchronized void log1这个方法,内部也是用的synchronized(this)实例方法的同步块。
4.静态方法中的同步块
测试代码:
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);
}
}
}
这两个方法不允许同时被线程访问。即使是同一个类的不同实例。如果第二个同步块不是同步在MyClass.class这个对象上。那么这两个方法可以同时被线程访问。