synchronized java 语言最简单的线程并发同步语法,上源码最快理解,
Resouce类表示并发资源
使用方法1.直接锁住某一个变量,如代码中的lock,注意这里lock必须为static的。如果不是static有什么后果?
public class Resource {
private static Object lock = new Object();
private Object unLock = new Object();
public void say() {
synchronized (unLock) {
System.out.println("come in unlock");
synchronized (lock) {
System.out.println("come in sleep");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
方法2,在方法前加上synchroized关键字
public synchronized void say() {
System.out.println("come in sleep");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
方法3,锁住class类
package com.learn.bao.mutithread;
public class Resource {
public void say() {
synchronized (Resource.class) {
System.out.println("come in unlock");
System.out.println("come in sleep");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
现在依次说一下其中的原理。
使用synchroized方法前要明白,这个关键字它到底锁住的是什么资源。
在多线程中,如果Resouce对象只有一个,上面几种方法都是可以的。
比如 下面的代码,都是可以的
package com.learn.bao.mutithread;
public class TestThread extends Thread {
private Resource r;
public TestThread(Resource r) {
this.r = r;
}
@Override
public void run() {
r.say();
}
}
package com.learn.bao.mutithread;
public class Main {
public static void main(String[] args) {
Resource r = new Resource();
for (int i = 0; i < 3; i++) {
TestThread t = new TestThread(r);
t.start();
}
}
}
为什么可以,因为所有线程都共用了一个对象Resouce,只有一个实例,所以加上synchroized关键词一定是线程安全的。
但是下面情况怎么办?
package com.learn.bao.mutithread;
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
Resource r = new Resource();
TestThread t = new TestThread(r);
t.start();
}
}
}
对于方法1来说如果lock不是静态变量就不能在线程中共享,所以也就无法实现线程安全,所以锁变量必须加上static关键字。
对于方法2由于锁的是Resource是对象本身,如果Resource有多个对象,自然无法实现线程安全,只能保证在同一个对象上是线程安全的,对于上面的情况就无法适用了。如果是多实例就需要手动加锁或者把方法改成静态。
方法3对于多实例和单实例而言都是安全的,因为它锁住的是class对象,在多线程中只有一份唯一的对象,所以是安全的,同static lock,这个也是我推荐的做法,代码比较简洁。
这里还要强调一下static synchroized静态同步方法它实际锁住的是Resouce这个类,这个类与他有多个实例无关,即使是new Resource().say(),强制创建新对象调用静态同步方法也还是线程安全的。