1. 概念:
- synchronized修饰静态方法,会给类加锁
- synchronized修饰实例方法,会给实例对象加锁
- synchronized代码块,锁住的是括号内的对象/类
2. 举个栗子:
2.1. 类锁:
两个线程同时访问,由于同步static方法,锁住的是类,所以必须等thread1执行完方法,释放锁后thread2才能进入testA方法。
public class RunnableThread implements Runnable {
@Override
public void run() {
try {
testA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private synchronized static void testA() throws InterruptedException {
System.out.println(Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(2);
}
public static void main(String[] args) {
RunnableThread thread1 = new RunnableThread ();
RunnableThread thread2 = new RunnableThread ();
new Thread(thread1, "thread1").start();
new Thread(thread2, "thread2").start();
}
}
2.2. 对象锁:
两个线程同时访问各自RunnableThread 任务,由于方法锁住的是对象,所以thread1和thread2都能同时进入testA方法
public class RunnableThread implements Runnable {
@Override
public void run() {
try {
testA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private synchronized void testA() throws InterruptedException {
System.out.println(Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(2);
}
public static void main(String[] args) {
RunnableThread thread1 = new RunnableThread ();
RunnableThread thread2 = new RunnableThread ();
new Thread(thread1, "thread1").start();
new Thread(thread2, "thread2").start();
}
}
如果像下面两个线程处理同一个RunnableThread 任务
`
多线程处理时,锁住的就是同一个thread1对象,所以两个线程不能同时进入testA方法
public static void main(String[] args) {
RunnableThread thread1 = new RunnableThread ();
new Thread(thread1, "thread1").start();
new Thread(thread1, "thread2").start();
}
2.3. 同步代码块:
synchronized代码块锁住的是括号内的对象/类;
·
如果同步代码块中同步静态变量(本例的count),那么锁住的对象(LOCK)也要是静态的,不然在多实例下可能不安全。
- 因为static变量会共享同一块内存区域(在构造函数中打印LOCK,地址是一样的),即能被类的所有实例共享
public class LockObject {
private static int count;
private final Object LOCK = new Object();
// private static final Object LOCK = new Object();
private final CountDownLatch countDownLatch;
public LockObject(CountDownLatch countDownLatch) {
// System.out.println(LOCK);
this.countDownLatch = countDownLatch;
}
public void testMethod() {
synchronized (LOCK) {
count++;
countDownLatch.countDown();
}
}
public static void main(String[] args) throws InterruptedException {
int size = 100000;
CountDownLatch latch = new CountDownLatch(size);
for (int i = 0; i < size; i++) {
new Thread(() -> new LockObject(latch).testMethod()).start();
}
latch.await();
System.out.println(count);
}
}
像上述,如果LOCK不是用static修饰的,还是多实例的
new Thread(() -> new LockObject(latch).testMethod())
`
那么LOCK就不是同一个对象,synchronized锁住的就不是同一个对象,结果输出count并不是100000