1.synchronized关键字修饰方法时,多线程访问被修饰的方法:
1.1 一个类,里面有两个方法A,B,都用Synchronized修饰了。当一个线程调用这个类的对象的A方法时候,另一个线程能调用该对象的B方法吗?
测试代码如下:
public class Test {
public static String TEMPLET_FILE = "report/custCare/ReturnReceipt.jasper";
public static void main(String[] args) throws BaseAppException, InterruptedException {
TestSyn testSyn = new Test.TestSyn();
Thread t1 = new Thread(()->{
testSyn.A();
});
Thread t2 = new Thread(()->{
testSyn.B();
});
t1.start();
t2.start();
}
static class TestSyn {
public synchronized void A() {
try {
System.out.println("before A " + Thread.currentThread().getName());
Thread.sleep(10000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after A " + Thread.currentThread().getName());
}
public synchronized void B() {
try {
System.out.println("before B " + Thread.currentThread().getName());
Thread.sleep(10000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after B " + Thread.currentThread().getName());
}
public TestSyn getIncetance() {
return new TestSyn();
}
}
}
运行结果:
before A Thread-0
after A Thread-0
before B Thread-1
after B Thread-1
在Thread-0开始执行方法A 打印before A Thread-0之后等待了10s,线程Thread-1在此期间处于阻塞状态
通过jstack查看jvm堆栈信息可以看出:当Thread-0 sleep 10s处于TIMED_WAITING状态时,Thread-1处于BLOCKED状态
当这种情况,Thread-1需要等待Thread-0执行完A释放锁,然后Thread-1获得锁之后才能执行B。
1.2 一个类,里面有两个方法A,B,其中B是静态方法,都用synchronized修饰了。当一个线程调用这个类的对象的A方法时候,另一个线程能调用该类的B方法吗?
测试代码如下
public class Test {
public static String TEMPLET_FILE = "report/custCare/ReturnReceipt.jasper";
public static void main(String[] args) throws BaseAppException, InterruptedException {
TestSyn testSyn = new Test.TestSyn();
Thread t1 = new Thread(()->{
testSyn.A();
});
Thread t2 = new Thread(()->{
Test.TestSyn.B();
});
t1.start();
t2.start();
}
static class TestSyn {
public synchronized void A() {
try {
System.out.println("before A " + Thread.currentThread().getName());
Thread.sleep(10000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after A " + Thread.currentThread().getName());
}
public synchronized static void B() {
try {
System.out.println("before B " + Thread.currentThread().getName());
Thread.sleep(10000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after B " + Thread.currentThread().getName());
}
public TestSyn getIncetance() {
return new TestSyn();
}
}
}
代码运行结果:
before B Thread-1
before A Thread-0
after A Thread-0
after B Thread-1
表示线程Thread-1调用方法B时,线程Thread-0开始调用方法A,不需要等待Thread-1释放锁。可以并发执行。
1.3 一个类,里面有两个方法A,B,其中A,B都是静态方法,都用Synchronized修饰了。当一个线程调用这个类的A方法时候,另一个线程能调用该类的B方法吗?
测试代码如下:
public class Test {
public static String TEMPLET_FILE = "report/custCare/ReturnReceipt.jasper";
public static void main(String[] args) throws BaseAppException, InterruptedException {
//TestSyn testSyn = new Test.TestSyn();
Thread t1 = new Thread(()->{
Test.TestSyn.A();
});
Thread t2 = new Thread(()->{
Test.TestSyn.B();
});
t1.start();
t2.start();
}
static class TestSyn {
public synchronized static void A() {
try {
System.out.println("before A " + Thread.currentThread().getName());
Thread.sleep(10000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after A " + Thread.currentThread().getName());
}
public synchronized static void B() {
try {
System.out.println("before B " + Thread.currentThread().getName());
Thread.sleep(10000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("after B " + Thread.currentThread().getName());
}
public TestSyn getIncetance() {
return new TestSyn();
}
}
}
运行结果:
before A Thread-0
after A Thread-0
before B Thread-1
after B Thread-1
在Thread-0开始执行方法A 打印before A Thread-0之后等待了10s,线程Thread-1在此期间处于阻塞状态
通过jstack查看jvm堆栈信息可以看出:当Thread-0 sleep 10s处于TIMED_WAITING状态时,Thread-1处于BLOCKED状态
D:\LDT-Orange\eclipse_oxygen\workspace\workspace_crm_v81c\java\practice\target\classes\com\test\yjw\practice>jps
10704 QuorumPeerMain
22576 Bootstrap
5536 Main
14456
20008 Jps
10908
22716 Test
6108
D:\LDT-Orange\eclipse_oxygen\workspace\workspace_crm_v81c\java\practice\target\classes\com\test\yjw\practice>jstack 22716
2019-12-26 20:40:18
Full thread dump OpenJDK 64-Bit Server VM (25.151-b12 mixed mode):
"DestroyJavaVM" #11 prio=5 os_prio=0 tid=0x00000000035e1060 nid=0x37e4 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Thread-1" #10 prio=5 os_prio=0 tid=0x000000001ba5aab0 nid=0x3700 waiting for monitor entry [0x000000001bf7f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.test.yjw.practice.Test$TestSyn.B(Test.java:71)
- waiting to lock <0x0000000780bcf448> (a java.lang.Class for com.test.yjw.practice.Test$TestSyn)
at com.test.yjw.practice.Test.lambda$1(Test.java:51)
at com.test.yjw.practice.Test$$Lambda$2/455659002.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Thread-0" #9 prio=5 os_prio=0 tid=0x000000001ba58da0 nid=0x3f34 waiting on condition [0x000000001be7f000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.test.yjw.practice.Test$TestSyn.A(Test.java:61)
- locked <0x0000000780bcf448> (a java.lang.Class for com.test.yjw.practice.Test$TestSyn)
at com.test.yjw.practice.Test.lambda$0(Test.java:48)
at com.test.yjw.practice.Test$$Lambda$1/1406718218.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Service Thread" #8 daemon prio=9 os_prio=0 tid=0x000000001b7a3600 nid=0x5a64 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x000000001a663b00 nid=0x2578 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x000000001a660530 nid=0x4770 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x000000001a65f450 nid=0x3498 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x000000001a66e250 nid=0x6c34 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
所以,当这种情况,Thread-1需要等待Thread-0执行完A释放锁,然后Thread-1获得锁之后才能执行B
总结:
1.当synchronized关键字修饰一个非静态方法时,要执行该方法需要获取相应的对象锁,同一个类中synchronized修饰的不同方法,对象锁是同一个。因此 当不同线程,用同一个对象调用同一个类中synchronized修饰的不同方法时,需要等待一个线程调用完方法释放锁之后,其他线程才有机会能获得锁并执行synchronized修饰的方法。
2.当synchronized关键字修饰一个静态方法时,要执行该方法需要获取相应的对象锁,但静态方法的锁是class对象锁,与实例对象锁不同,因此在一个线程获得实例对象锁的情况下,另一个线程仍可以获得class对象锁。