synchronized(object) 非this对象锁
package ch02.test4;
import java.util.ArrayList;
import java.util.List;
class MyList {
private List list = new ArrayList();
public synchronized void add(String data) {
list.add(data);
}
public synchronized int getSize() {
return list.size();
}
}
class MyService {
public MyList addServiceMethod(MyList list, String data) {
try {
if(list.getSize() < 1) {
Thread.sleep(2000);
list.add(data);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return list;
}
}
class MyThread1 extends Thread {
private MyList list;
public MyThread1(MyList list) {
this.list = list;
}
@Override
public void run() {
super.run();
MyService myService = new MyService();
myService.addServiceMethod(list,"A");
}
}
class MyThread2 extends Thread {
private MyList list;
public MyThread2(MyList list) {
this.list = list;
}
@Override
public void run() {
super.run();
MyService myService = new MyService();
myService.addServiceMethod(list,"B");
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
MyList list = new MyList();
MyThread1 myThread1 = new MyThread1(list);
myThread1.setName("A");
myThread1.start();
MyThread2 myThread2 = new MyThread2(list);
myThread2.setName("B");
myThread2.start();
Thread.sleep(6000);
System.out.println("listSize="+list.getSize());
}
}
output:
listSize=2
出现“脏读”的原因是两个线程以异步的方式返回list的大小。
解决方法:
修改MyService类:
class MyService {
public MyList addServiceMethod(MyList list, String data) {
try {
synchronized (list) {
if (list.getSize() < 1) {
Thread.sleep(2000);
list.add(data);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return list;
}
}
修改之后,对同一个list对象,在代码块中,线程A始终保持对list对象的锁,因而线程B在线程A完成add操作之前不能执行list的同步方法。
synchronized静态同步方法和synchronized(class)代码块
- synchronized静态同步方法
synchronized加到static方法是给Class类上锁,而加到非static方法是给对象上锁。
package ch02.test5;
public class Test {
Service service = new Service();
public static void main(String[] args) {
Service service = new Service();
ThreadA threadA = new ThreadA(service);
threadA.setName("a");
threadA.start();
ThreadB threadB = new ThreadB(service);
threadB.setName("b");
threadB.start();
ThreadC threadC = new ThreadC(service);
threadC.setName("c");
threadC.start();
}
}
class Service {
synchronized public static void printA() {
try {
System.out.println("线程"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"进入printA");
Thread.sleep(3000);
System.out.println("线程"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"离开printA");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized public static void printB() {
System.out.println("线程"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"进入printB");
System.out.println("线程"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"离开printB");
}
synchronized public void printC() {
System.out.println("线程"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"进入printC");
System.out.println("线程"+Thread.currentThread().getName()+"在"+System.currentTimeMillis()+"离开printC");
}
}
class ThreadA extends Thread {
private Service service;
public ThreadA(Service service) {
this.service = service;
}
@Override
public void run() {
super.run();
service.printA();
}
}
class ThreadB extends Thread {
private Service service;
public ThreadB(Service service) {
this.service = service;
}
@Override
public void run() {
super.run();
service.printB();
}
}
class ThreadC extends Thread {
private Service service;
public ThreadC(Service service) {
this.service = service;
}
@Override
public void run() {
super.run();
service.printC();
}
}
output:
线程a在1599825585555进入printA
线程c在1599825585564进入printC
线程c在1599825585564离开printC
线程a在1599825588556离开printA
线程b在1599825588556进入printB
线程b在1599825588556离开printB
从结果上来看,线程A和线程B之间是同步的,AC之间以及BC之间是异步的。
原因是线程A和线程B分别持有不同的锁,线程A持有的是Class锁,线程B持有的是对象锁。