1.同步方法
public class Test {
synchronized public static void testMethod(){}
public static void main(String[] args) {
testMethod();
}
}
// 实现class文件的反汇编
java -c -v *.class
从字节码文件中可以看到同步方法根据flags标志中的ACC_SYNCHRONIZED来判别是否是同步方法。
1.1 锁对象
同步方法中并不是锁方法而是锁当前类的对象
注:静态同步方法中锁是当前类,而不是对象。
- 测试:methodA为同步方法,methodB为非同步方法,线程A调用methodA,线程B调用methodB。
TestMethod.java
public class TestMethod {
synchronized public void methodA() {
try {
System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public void methodB() {
try {
System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
ThreadA.java
public class ThreadA extends Thread{
private TestMethod testMethod;
public ThreadA(TestMethod testMethod) {
super();
this.testMethod = testMethod;
}
@Override
public void run() {
super.run();
testMethod.methodA();
}
}
ThreadB.java
public class ThreadA extends Thread{
private TestMethod testMethod;
public ThreadA(TestMethod testMethod) {
super();
this.testMethod = testMethod;
}
@Override
public void run() {
super.run();
testMethod.methodA();
}
}
Test.java
public class Test {
public static void main(String[] args) {
TestMethod testMethod = new TestMethod();
ThreadA threadA = new ThreadA(testMethod);
threadA.setName("a");
ThreadB threadB = new ThreadB(testMethod);
threadB.setName("b");
threadA.start();
threadB.start();
}
}
运行结果:
methodA start ThreadName= a startTime=1690358535034
methodB start ThreadName= b startTime=1690358535034
methodA start ThreadName= a endTime=1690358540035
methodB start ThreadName= b endTime=1690358540035
结论:从结果可以看出,线程A持有TestMethod对象锁,线程B可以调用TestMethod的非同步方法。
- 测试:methodA和methodB为同步方法,线程A调用methodA,线程B调用methodB。
TestMethod.java
// 将methodB也修改为同步方法
public class TestMethod {
synchronized public void methodA() {
try {
System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
synchronized public void methodB() {
try {
System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
结果:
methodA start ThreadName= a startTime=1690359406773
methodA start ThreadName= a endTime=1690359411785
methodB start ThreadName= b startTime=1690359411785
methodB start ThreadName= b endTime=1690359416796
结论:从结果可以看出,线程A先持有TestMethod对象锁,虽然线程B调用的是methodB方法,但是也要等A释放锁之后才能执行。
2.同步代码块
public class Test2 {
public void myMethod() {
synchronized (this) {
int age = 100;
}
}
public static void main(String[] args) {
Test2 test2 = new Test2();
test2.myMethod();
}
}
从字节码文件中可以看到同步代码块根据monitorenter和monitorexit来进行同步处理。
2.1 锁对象
和同步方法一样,同步代码块synchronized (this)锁的也是对象。
测试:
TestMethod.java
public class TestMethod {
public void methodA() {
try {
synchronized (this) {
System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public void methodB() {
try {
synchronized (this) {
System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
结果:
methodA start ThreadName= a startTime=1690361223642
methodA start ThreadName= a endTime=1690361228654
methodB start ThreadName= b startTime=1690361228654
methodB start ThreadName= b endTime=1690361233654
注:此时(this)是锁的同一对象,所以methodA和methodB同步执行,如果使用不同对象锁,则互不影响。
测试:
TestMethod.java
public class TestMethod {
// 也可以使用非对象做为锁。
private String lock = new String();
public void methodA() {
try {
synchronized (this) {
System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodA start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public void methodB() {
try {
synchronized (lock) {
System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " startTime=" + System.currentTimeMillis());
Thread.sleep(5000);
System.out.println("methodB start ThreadName= " + Thread.currentThread().getName() + " endTime=" + System.currentTimeMillis());
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
结果:
methodA start ThreadName= a startTime=1690361599813
methodB start ThreadName= b startTime=1690361599813
methodA start ThreadName= a endTime=1690361604820
methodB start ThreadName= b endTime=1690361604820
结论:从结果可以看出,虽然methodA和methodB中都存在同步代码块,但是因为锁对象不同,所以两个同步代码块的调用互不影响。