synchronized
关键字涉及到锁的概念,在java中,synchronized锁大家又通俗的称为:方法锁,对象锁 和 类锁 。关于锁只有以下两点:
- 无论是修饰方法还是修饰代码块都是 对象锁,当一个线程访问一个带
synchronized
方法时,由于对象锁的存在,所有加synchronized
的方法都不能被访问(前提是在多个线程调用的是同一个对象实例中的方法) - 无论是修饰静态方法还是锁定某个对象,都是 类锁.一个class其中的静态方法和静态变量在内存中只会加载和初始化一份,所以,一旦一个静态的方法被申明为
synchronized
,此类的所有的实例化对象在调用该方法时,共用同一把锁,称之为类锁
1、对象锁
1.1 对象锁写法一:修饰方法
synchronized
修饰普通方法,锁定的是当前对象,
public class SyncTest {
public synchronized void methon(){
//方法体
}
}
一次只能有一个线程进入同一个对象实例的method()
方法。
1.2 对象锁的写法二:修饰代码块,锁实例对象
public class SyncObjectTest implements Runnable{
private int count = 0;
@Override
public void run() {
String name = Thread.currentThread().getName();
if ("add".equalsIgnoreCase(name)) {
addCount();
} else {
delCount();
}
}
public void addCount() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
try {
count = count + 1;
System.out.println(Thread.currentThread().getName() + "[" + i + "]: " + count);
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void delCount() {
synchronized (this) {
for (int i = 0; i < 5; i++) {
try {
count = count - 1;
System.out.println(Thread.currentThread().getName() + "[" + i + "]: " + count);
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
SyncObjectTest objectTest = new SyncObjectTest();
Thread thread = new Thread(objectTest, "add");
Thread thread1 = new Thread(objectTest, "del");
thread.start();
thread1.start();
}
}
输出结果:
add[0]: 1
add[1]: 2
add[2]: 3
add[3]: 4
add[4]: 5
del[0]: 4
del[1]: 3
del[2]: 2
del[3]: 1
del[4]: 0
根据输出结果显示,说明在同一个对象实例中,synchronized修饰的所有方法不能并行执行
2、类锁
2.1 类锁写法一:修饰静态方法
public class SyncClassObject implements Runnable {
private static int count = 0;
@Override
public void run() {
method();
}
public synchronized static void method() {
for (int i = 0; i < 5; i++) {
count = count + 1;
System.out.println(Thread.currentThread().getName() + "[" + i + "]: " + count);
}
}
public static void main(String[] args) {
SyncClassObject class1 = new SyncClassObject();
SyncClassObject class2 = new SyncClassObject();
Thread first = new Thread(class1, "first");
Thread second = new Thread(class2, "second");
first.start();
second.start();
}
}
输出结果:
first[0]: 1
first[1]: 2
first[2]: 3
first[3]: 4
first[4]: 5
second[0]: 6
second[1]: 7
second[2]: 8
second[3]: 9
second[4]: 10
上述结果可知在类锁的情况下,即便创建了两个对象,类锁依然生效。
2.2 类锁写法二:修饰代码块、锁类对象
public class SyncClassTest {
public void test1() {
synchronized (SyncClassTest.class) { //静态方法块类锁
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static synchronized void test2() { //静态方法类锁
int i = 5;
while (i-- >0 ){
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SyncClassTest syncClassTest = new SyncClassTest();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
syncClassTest.test1();
}
});
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
SyncClassTest.test2();
}
});
thread.start();
thread1.start();
}
}
输出结果:
Thread-0: 4
Thread-0: 3
Thread-0: 2
Thread-0: 1
Thread-0: 0
Thread-1 : 4
Thread-1 : 3
Thread-1 : 2
Thread-1 : 1
Thread-1 : 0
上述结果表示类锁已生效。
其实,类锁修饰方法和代码块的效果和对象锁是一样的,因为类锁只是一个抽象出来的概念,只是为了区别静态方法的特点,因为静态方法是所有对象实例共用的,所以对应着synchronized修饰的静态方法的锁也是唯一的,所以抽象出来个类锁。
3、同时修饰静态和非静态方法
public class SyncClassTest {
public synchronized void test1() { //类锁
int i = 5;
while (i-- > 0) {
System.out.println(Thread.currentThread().getName() + ": " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static synchronized void test2() { //静态方法类锁
int i = 5;
while (i-- >0 ){
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SyncClassTest syncClassTest = new SyncClassTest();
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
syncClassTest.test1();
}
});
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
SyncClassTest.test2();
}
});
thread.start();
thread1.start();
}
}
输出结果:
Thread-0: 4
Thread-1 : 4
Thread-1 : 3
Thread-0: 3
Thread-0: 2
Thread-1 : 2
Thread-1 : 1
Thread-0: 1
Thread-1 : 0
Thread-0: 0
上面的synchronized
同时修饰静态方法和实例方法,结果交替运行,证明类锁和对象锁是两个不同的锁,控制不同的区域,互不干扰.