昨天部门新人培训,讲到synchronized关键字的问题,发现对于synchronized的使用有些不太懂,于是今天总结一下:
很久之前我在Java编程思想之并发编程这篇文章中写过,什么时候该使用同步?运用Brian同步规则:如果你正在写一个变量,它可能接下来将被另一个线程读取,或者正在读取一个上一次已经被另一个写过的变量,那么你必须使用同步,并且读写线程必须使用相同的监视器锁同步。
同步分为两种,一种是多个线程共享同一个资源,该资源同一时刻只能让一个线程访问,对共享资源的互斥访问,利用synchronized关键字或者Lock等实现。另一种是多个线程协作解决某一个问题,某个线程必须在另一个线程之前或者之后完成,线程之间的顺序问题,利用wait()和notify()实现。
synchronized的作用对象
- 总体来说synchronized关键字可以作用于变量、对象、函数和类名上面;函数又包括静态函数和非静态函数两种。
- 无论synchronized关键字加载方法上还是对象上,它取得的锁都是对象,而不是一段代码或函数当做锁。
- 每个对象只有一个锁与之相关联。
synchronized关键字的作用域
- 某个对象实例内,synchronized get5(){},synchronized (this) {}这两种方式可以防止多个线程访问同一对象的synchronized 方法或者synchronized (this) {}所包含的代码块。
- 某个对象内,如下代码所示:可以防止多个线程访问同一对象。
private Object staticLock = new Object();
public void get1() {
synchronized (staticLock) {
System.out.println("void get1() synchronized (staticLock)");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("释放资源" + "staickLock");
}
- 以上两种是在对象的范围内,也就是说不同对象是互不干扰的。
- 某个类的范围内,如下面两种方式:他们锁的对象的这个类的class文件。
public void get2(){
synchronized (SynchronizeEntity.class) {
System.out.println("void get2() synchronized (SynchronizeEntity.class)");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("释放资源" + "SynchronizeEntity.class");
}
public synchronized static void get3(){
System.out.println("synchronized static void get3()");
}
- 只要锁的对象不一样,在不同线程就可以同时访问。
package com.xqq.entity.test;
public class SynchronizeEntity {
private Object staticLock = new Object();
public void get1() {
synchronized (staticLock) {
System.out.println("void get1() synchronized (staticLock)");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("释放资源" + "staickLock");
}
public void get2(){
synchronized (SynchronizeEntity.class) {
System.out.println("void get2() synchronized (SynchronizeEntity.class)");
// 睡眠 占用所资源不释放
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("释放资源" + "SynchronizeEntity.class");
}
public synchronized static void get3(){
System.out.println("synchronized static void get3()");
}
public void get4() {
synchronized (this) {
System.out.println("void get4() synchronized (this)");
}
System.out.println("释放资源" + "this");
}
public synchronized void get5() {
System.out.println("synchronized void get5()");
}
}
package com.xqq.entity.test;
public class Test {
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
public void run() {
// 访问synchronized (SynchronizeEntity.class) {}修饰的方法,属于类级别
SynchronizeEntity test1 = new SynchronizeEntity();
test1.get2();
}
}).start();
Thread.sleep(1000);
new Thread(new Runnable() {
// 访问 synchronized void get5() {}方法,属于对象级别
public void run() {
SynchronizeEntity test1 = new SynchronizeEntity();
test1.get5();
}
}).start();
}
}
运行结果:
void get2() synchronized (SynchronizeEntity.class)
synchronized void get5()
释放资源SynchronizeEntity.class
由结果可以看出:访问对象级别的同步方法并不需要等待类级别的方法释放 锁资源。