synchronized 可以锁类方法(静态方法) 或者 普通方法
修饰普通方法
1.先看单个对象代码
package com.thread;
public class SynchronizedTest {
synchronized public void function1() throws InterruptedException {
String name = Thread.currentThread().getName();
for (int i = 0; i < 5; i++){
System.out.println("function1 " + name);
Thread.sleep(1000);
}
}
synchronized public void function2() throws InterruptedException {
String name = Thread.currentThread().getName();
for (int i = 0; i < 5; i++){
System.out.println("function2 " + name);
Thread.sleep(1000);
}
}
public static void main(String[] args) throws InterruptedException {
SynchronizedTest s1 = new SynchronizedTest();
new Thread(() -> {
System.out.println("Thread1 is start");
try {
s1.function1();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread1 is end");
}).start();
new Thread(() -> {
System.out.println("Thread2 is start");
try {
s1.function2();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread2 is end");
}).start();
}
}
首先看,我们创建的对象s1,在不同线程分别执行不同的两个普通方法(实例方法),因为synchronized 锁住的是对象(对象锁),所以按照执行顺序是function1 再试function2
纵然function2想去执行方法,但是,因为对象锁锁住的是s1对象,所以必须等到function1执行完毕function2中才能获得锁执行方法
2.再看多个对象代码
为了验证这个,我们再去建立一个对象s2,开启线程执行function2.
package com.thread;
public class SynchronizedTest {
synchronized public void function1() throws InterruptedException {
String name = Thread.currentThread().getName();
for (int i = 0; i < 5; i++){
System.out.println("function1 " + name);
Thread.sleep(1000);
}
}
synchronized public void function2() throws InterruptedException {
String name = Thread.currentThread().getName();
for (int i = 0; i < 5; i++){
System.out.println("function2 " + name);
Thread.sleep(1000);
}
}
public static void main(String[] args) throws InterruptedException {
SynchronizedTest s1 = new SynchronizedTest();
SynchronizedTest s2 = new SynchronizedTest();
new Thread(() -> {
System.out.println("Thread1 is start");
try {
s1.function1();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread1 is end");
}).start();
new Thread(() -> {
System.out.println("Thread2 is start");
try {
s1.function2();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread2 is end");
}).start();
new Thread(() -> {
System.out.println("Thread3 is start");
try {
s2.function2();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread3 is end");
}).start();
}
}
执行结果如下
丛中可以看出,对象二s2 并没有收到s1的影响,自己个儿跑自己个儿的方法了,所以说synchronized 修饰普通方法,仅仅对该实例对象有限制,其他对象不会有影响。所以锁住的是this 实例对象。
修饰类方法
直接上代码
package com.thread;
public class SynchronizedTest {
synchronized public static void function1() throws InterruptedException {
String name = Thread.currentThread().getName();
for (int i = 0; i < 5; i++){
System.out.println("function1 " + name);
Thread.sleep(1000);
}
}
synchronized public static void function2() throws InterruptedException {
String name = Thread.currentThread().getName();
for (int i = 0; i < 5; i++){
System.out.println("function2 " + name);
Thread.sleep(1000);
}
}
public static void main(String[] args) throws InterruptedException {
SynchronizedTest s1 = new SynchronizedTest();
SynchronizedTest s2 = new SynchronizedTest();
new Thread(() -> {
System.out.println("Thread1 is start");
try {
s1.function1();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread1 is end");
}).start();
new Thread(() -> {
System.out.println("Thread2 is start");
try {
s1.function2();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread2 is end");
}).start();
new Thread(() -> {
System.out.println("Thread3 is start");
try {
s2.function2();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread3 is end");
}).start();
}
}
运行结果如下
可以看出,不同类实例对象的执行按照顺序走了,也就是:虽然是不同的对象,但是s1 s2 都是同一个类的不同对象,这样的话,synchronized 修饰类方法(静态方法),所有对象持有的都是一把锁,也就是SynchronizedTest.class
现有一段代码
public class TestStaticParam {
private static Integer ticket = 100;
public void ticket(){
synchronized (this){
while (ticket > 0){
try {
Thread.sleep(100);
System.out.println(Thread.currentThread().getName()+":"+"减少前:" + ticket +"减少后:"+(--ticket));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
TestStaticParam p1 = new TestStaticParam();
TestStaticParam p2 = new TestStaticParam();
new Thread(() -> p1.ticket()).start();
new Thread(() -> p2.ticket()).start();
}
}
synchronized 锁住的是this , 该方法是一个普通实例方法,所以this值得也就是实例变量,最后执行的结果肯定有问题!因为所得是实例变量,两个变量互不干扰,肯定影响数据ticket!
如何解决?
1.synchronized this 改成 当前类.class,也就是TestStaticParam .class,这样,按照之前讲过的,该锁就锁住了整个TestStaticParam ,而两个实例变量都是该类产生的,所以,线程跑起来只有线程一 抢到了锁,只想完毕整个循环就结束了!没有线程2什么事
2.synchronized 改成ticket ,这样,锁住的就是 该ticket 对象,两个线程谁抢到该锁,谁就先执行,而synchronized 具有原子性和可见性,从而达到了保护ticket 数据的目的