synchronized关键字小结(一)

时间:2023-03-09 19:27:58
synchronized关键字小结(一)

1. synchronized同步方法

1) synchronized修饰方法,表示方法是同步的,当某线程进入并拿到当前整个对象的锁时

a. 其他synchronized方法排队等锁

b. 非synchronized方法可异步执行

示例代码(折叠)

 package com.khlin.thread;

 public class SynchronizedTest {

     public static void main(String[] args) {
Service service = new Service();
/**
* A B 两个方法是同步的,因此访问A时候,要等A方法执行完,A线程释放锁,B线程才能拿到锁从而访问B方法。
* 而C方法并不是同步的,可以异步执行
*/
ThreadA threadA = new ThreadA(service);
threadA.start(); ThreadB threadB = new ThreadB(service);
threadB.start(); ThreadC threadC = new ThreadC(service);
threadC.start();
}
} class ThreadA extends Thread { private Service service; public ThreadA(Service service) {
this.service = service;
} public void run() {
super.run();
service.printA();
}
} class ThreadB extends Thread { private Service service; public ThreadB(Service service) {
this.service = service;
} public void run() {
super.run();
service.printB();
}
} class ThreadC extends Thread { private Service service; public ThreadC(Service service) {
this.service = service;
} public void run() {
super.run();
service.printC();
}
} class Service {
public synchronized void printA() { System.out.println("enter printA. thread name: "
+ Thread.currentThread().getName()); try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} System.out.println("leaving printA. thread name: "
+ Thread.currentThread().getName());
} public synchronized void printB() { System.out.println("enter printB. thread name: "
+ Thread.currentThread().getName()); System.out.println("leaving printB. thread name: "
+ Thread.currentThread().getName());
} public void printC() { System.out.println("enter printC. thread name: "
+ Thread.currentThread().getName()); System.out.println("leaving printC. thread name: "
+ Thread.currentThread().getName());
}
}

synchronized方法

运行结果:

synchronized关键字小结(一)

2) 拥有锁重入的功能,当一个线程获得一个对象锁之后 ,再次请求此对象锁的时候是可以再次获得的。

示例代码,修改上面示例代码,在A方法后面调用B方法,可以再次获得锁,运行结果:

synchronized关键字小结(一)

3) 重写方法后,synchronized关键字并不继承。但没有被重写的方法,仍然是同步的。

 package com.khlin.thread;

 public class SynchronizedTest {

     public static void main(String[] args) {
/**
* 子类方法的实现若调用了父类的同步方法,一样有效
*/
SubService service = new SubService();
/**
* A B 两个方法是同步的,因此访问A时候,要等A方法执行完,A线程释放锁,B线程才能拿到锁从而访问B方法。
* 而C方法并不是同步的,可以异步执行
*/
ThreadA threadA = new ThreadA(service);
threadA.setName("threadA");
threadA.start(); ThreadB threadB = new ThreadB(service);
threadB.setName("threadB");
threadB.start(); ThreadC threadC = new ThreadC(service);
threadC.setName("threadC");
threadC.start();
}
} class ThreadA extends Thread { private Service service; public ThreadA(Service service) {
this.service = service;
} public void run() {
super.run();
service.printA();
// service.printB();
}
} class ThreadB extends Thread { private Service service; public ThreadB(Service service) {
this.service = service;
} public void run() {
super.run();
service.printB();
}
} class ThreadC extends Thread { private Service service; public ThreadC(Service service) {
this.service = service;
} public void run() {
super.run();
service.printC();
}
} class Service {
public synchronized void printA() { System.out.println("enter printA. thread name: "
+ Thread.currentThread().getName()); try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} System.out.println("leaving printA. thread name: "
+ Thread.currentThread().getName()); // printB();
} public synchronized void printB() { System.out.println("enter printB. thread name: "
+ Thread.currentThread().getName()); System.out.println("leaving printB. thread name: "
+ Thread.currentThread().getName());
} public void printC() { System.out.println("enter printC. thread name: "
+ Thread.currentThread().getName()); System.out.println("leaving printC. thread name: "
+ Thread.currentThread().getName());
}
} class SubService extends Service { public void printSubA() {
System.out.println("enter printSubA. thread name: "
+ Thread.currentThread().getName());
printA();
System.out.println("leaving printSubA. thread name: "
+ Thread.currentThread().getName());
}
}

运行结果和1)是一样的。

2. synchronized同步代码块

同步代码块,通过synchronized(一个对象)的写法,把一个代码块变成同步的。

其中,括号里待同步的对象,也可以使用this关键字,指向当前对象,这时与synchronized方法效果是一样的。

1) 被同步的对象是this的情况

与synchronized方法效果一样,示例代码:

 package com.khlin.thread;

 public class SynchronizedTestSecond {

     public static void main(String[] args) {
ServiceSecond service = new ServiceSecond(); ThreadAA threadAA = new ThreadAA(service);
threadAA.setName("ThreadAA");
threadAA.start(); try {
Thread.sleep(500L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} ThreadBB threadBB = new ThreadBB(service);
threadBB.setName("ThreadBB");
threadBB.start();
} } class ServiceSecond { public void methodA() {
String threadName = Thread.currentThread().getName();
synchronized (this) {
System.out.println("invoke methodA. " + threadName);
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("finish invoking methodA. " + threadName);
}
} public synchronized void methodB() {
String threadName = Thread.currentThread().getName();
System.out.println("invoke methodB. " + threadName);
System.out.println("finish invoking methodA. " + threadName);
}
} class ThreadAA extends Thread {
ServiceSecond service = new ServiceSecond(); public ThreadAA(ServiceSecond service) {
this.service = service;
}
public void run() {
service.methodA();
}
} class ThreadBB extends Thread {
ServiceSecond service = new ServiceSecond(); public ThreadBB(ServiceSecond service) {
this.service = service;
}
public void run() {
service.methodB();
}
}

运行结果:

synchronized关键字小结(一)

2) 被同步的对象非this的情况

假设synchronized(x),此时,访问x对象里的同步方法,是同步访问的。

而访问主对象的同步方法,不受同步影响,属于异步。

让我们把上面的代码改为,synchronized(operation),锁住另一个对象。

 package com.khlin.thread;

 public class SynchronizedTestSecond {

     public static void main(String[] args) {
ServiceSecond service = new ServiceSecond(); /**
* 锁住了operation对象,该对象的同步方法必须等待锁
* 而methodB并不属于该对象,ServiceSecond对象的锁,其实线程AA并没有获取,所以线程BB可以异步访问methodB方法。
*/ ThreadAA threadAA = new ThreadAA(service);
threadAA.setName("ThreadAA");
threadAA.start(); try {
Thread.sleep(500L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} ThreadBB threadBB = new ThreadBB(service);
threadBB.setName("ThreadBB");
threadBB.start();
} } class ServiceSecond { private ServiceOperation operation = new ServiceOperation(); public void methodA() {
String threadName = Thread.currentThread().getName(); synchronized (operation) {
System.out.println("invoke methodA. " + threadName);
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("finish invoking methodA. " + threadName);
}
} public synchronized void methodB() {
String threadName = Thread.currentThread().getName();
System.out.println("invoke methodB. " + threadName);
System.out.println("finish invoking methodB. " + threadName);
}
} class ServiceOperation { public synchronized void methodOperation() {
System.out.println("this is operation method.");
}
} class ThreadAA extends Thread {
ServiceSecond service = new ServiceSecond(); public ThreadAA(ServiceSecond service) {
this.service = service;
}
public void run() {
service.methodA();
}
} class ThreadBB extends Thread {
ServiceSecond service = new ServiceSecond(); public ThreadBB(ServiceSecond service) {
this.service = service;
}
public void run() {
service.methodB();
}
}

运行结果:

synchronized关键字小结(一)

因为线程BB在访问methodB的时候,service对象的锁并没有被占用着,所以可以直接占用并调用方法。

3. 静态方法的synchronized方法和synchronized(class)方法

这是对类加锁,注意,在java中,类是一种特殊的对象。

原理与上述的非静态方法同步是一样的,不再赘述。

示例代码:

 package com.khlin.thread;

 public class SynchronizedStatic {

     public static void main(String[] args) {
ThreadAAA threadAAA = new ThreadAAA();
threadAAA.setName("ThreadAAA");
threadAAA.start(); try {
Thread.sleep(500L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} ThreadBBB threadBBB = new ThreadBBB();
threadBBB.setName("ThreadBBB");
threadBBB.start();
}
} class StaticService {
public synchronized static void methodA()
{
String threadname = Thread.currentThread().getName(); System.out.println("invoking methodA. " + threadname); try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} System.out.println("finish methodA. " + threadname);
} public synchronized static void methodB()
{
String threadname = Thread.currentThread().getName(); System.out.println("invoking methodB. " + threadname); System.out.println("finish methodB. " + threadname);
}
} class ThreadAAA extends Thread { public void run() {
StaticService.methodA();
}
} class ThreadBBB extends Thread { public void run() {
StaticService.methodB();
}
}

运行结果:

synchronized关键字小结(一)