并发编程中,互斥是很关键的一块.java中方法如我所知有二:
1.synchronized同步,
2.java.util.concurrent.locks.ReentrantLock加锁
个人认为两种方式原理上一样的,此文先讲synchronized同步方法.
synchronized 的使用方式两种:1直接加在方法上,2加在代码块上.
synchronized 加在方法上默认使用this对象来做为锁,这时这个对象上的所有synchronized 修饰的实例方法别的线程都无法调用,只有当前获得锁的线程可以执行.
synchronized加在代码块上的话,指定this做为锁的话,同样要和同步实例方法竞争这个锁,所以也只能有一个线程执行.
测试一如下,运行结果hello,t2会在10s之后输出.
T1 get lock
hello ,t1
hello,t2
public class SynObj {
public synchronized void sysHello1() {
System.out.println("T1 get lock");
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("hello ,t1");
}
public void sysHello2() {
synchronized (this) {
System.out.println("hello,t2");
}
}
}
public static void main(String[] args) {
final SynObj obj = new SynObj();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
obj.sysHello1();
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
obj.sysHello2();
}
});
t2.start();
}
如果使用不同的对象做为锁对象,则同时可以有两个线程可以执行,这种方式适合同一实例中有多个公共资源的并发控制.
测试二如下,结果线程二比线程一先执行,说明线程二并不和线程一竞争同一个锁.
T1 get lock
hello,t2
hello ,t1
package syn;
public class SynObj {
static private class Lock {
};
private Object lock2 = new Object();
private Lock lock = new Lock();
public synchronized void sysHello1() {
System.out.println("T1 get lock");
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("hello ,t1");
}
public void sysHello2() {
synchronized (lock2) {
System.out.println("hello,t2");
}
}
public static void main(String[] args) {
final SynObj obj = new SynObj();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
obj.sysHello1();
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
obj.sysHello2();
}
});
t2.start();
}
}
为了深入对比一下类方法的步和实例方法的同步再改一下测试.
synchronized 加在实例方法上只能对访问同一个实例的多个线的线程起作用,使他们互斥.
synchronized 加在类方法上(static方法)则整个class体系下的任一实例的同步方法都被同一个锁所监视,所有线程访问这个class下不同实例也要竞争锁.
测试三结果,线程二先运行完成,说明线程一和线程二并不竞争同一个锁.
t2@obj2
t1@obj
package syn;
public class SynObj {
static private class Lock {
};
private Object lock2 = new Object();
private Lock lock = new Lock();
public synchronized void sysHello1(String str) {
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(str);
}
public void sysHello2(String str) {
synchronized (lock2) {
System.out.println(str);
}
}
public static void main(String[] args) {
final SynObj obj = new SynObj();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
obj.sysHello1("t1@obj");
}
});
t1.start();
final SynObj obj2 = new SynObj();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
obj2.sysHello2("t2@obj2");
}
});
t2.start();
}
}
测试四如下.类方法之间不同实例同样竞争.
t1@obj
t2@obj2
package syn;
public class SynObj {
static private class Lock {
};
private Object lock2 = new Object();
private Lock lock = new Lock();
public synchronized static void sysHello1(String str) {
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(str);
}
public synchronized static void sysHello2(String str) {
System.out.println(str);
}
public static void main(String[] args) {
final SynObj obj = new SynObj();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
obj.sysHello1("t1@obj");
}
});
t1.start();
final SynObj obj2 = new SynObj();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
obj2.sysHello2("t2@obj2");
}
});
t2.start();
}
}
测试五:利用static lock来使所有class的实例同步竞争.
t1@obj
t2@obj2
package syn;
public class SynObj {
static private class Lock {
};
private static Lock lock = new Lock();
public void sysHello1(String str) {
synchronized (lock) {
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(str);
}
}
public void sysHello2(String str) {
synchronized (lock) {
System.out.println(str);
}
}
public static void main(String[] args) {
final SynObj obj = new SynObj();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
obj.sysHello1("t1@obj");
}
});
t1.start();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
final SynObj obj2 = new SynObj();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
obj2.sysHello2("t2@obj2");
}
});
t2.start();
}
}