synchronized理解
synchronized是一个排它锁,既能够锁方法,又能够锁代码块。
用于实现线程同步,多个线程依次获取资源。
synchronized 在方法上,且非静态方法
此时锁的是方法调用者。
示例:两个线程
结果:先输入B,在输出A
public class Test {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
try {
data.fun01();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(()->{
try {
data.fun02();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
class Data{
public void fun01() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("A----1");
}
public void fun02() throws InterruptedException {
TimeUnit.SECONDS.sleep(1);
System.out.println("B----2");
}
}
在方法上加上synchronized ,就会出现:
3秒后输出A
再过1秒,输出B的情况。
package com.springdemo.demo;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) {
Data data = new Data();
new Thread(()->{
try {
data.fun01();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(()->{
try {
data.fun02();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
class Data{
public synchronized void fun01() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("A----1");
}
public synchronized void fun02() throws InterruptedException {
TimeUnit.SECONDS.sleep(1);
System.out.println("B----2");
}
}
如果将fun02()上的synchronized 去掉就会出现,先输出B再输出A的情况。
同样的如果是两个对象,
Data data = new Data();
Data data2 = new Data();
这两个对象分别调用fun01,和fun02,也不会出现资源争夺的情况,
结果就是先输出B,再输出A。
synchronized关键字在静态方法上
class Data{
public synchronized static void fun01() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println("A----1");
}
public synchronized static void fun02() throws InterruptedException {
System.out.println("B----2");
}
}
结果表现:则是3秒后,先输出A,再输出B。依然对资源进行线程的排队获取的处理。
synchronized关键字修饰代码块
public static void main(String[] args) {
Data2 data2 = new Data2();
for (int i = 0;i<5;i++){
new Thread(()->{
try {
data2.fun3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
class Data2{
public void fun3() throws InterruptedException {
System.out.println("3----start");
TimeUnit.SECONDS.sleep(3);
System.out.println("3----end");
}
}
此时结果是:输出5个start,过3秒后,再输出5个end。
加上synchronized 锁代码块,this锁的对象
public void fun3() throws InterruptedException {
synchronized (this){
System.out.println("3----start");
TimeUnit.SECONDS.sleep(3);
System.out.println("3----end");
}
}
结果:此时会排队,一个start,一个end,循环5次。
此时的this,代表当前的实例化对象。此时5个线程,公用一个data2 对象。
将data2放到循环中
public static void main(String[] args) {
for (int i = 0;i<5;i++){
new Thread(()->{
try {
Data2 data2 = new Data2();
data2.fun3();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
此时,又是同时开始,同时结束,输出5次start,再输出5次end。
如果synchronized (Data2.class),此时锁的是Data2这个类。
public void fun3() throws InterruptedException {
synchronized (Data2.class){
System.out.println("3----start");
TimeUnit.SECONDS.sleep(3);
System.out.println("3----end");
}
}
此时尽管循环创建新的data2对象,也依然会排队。start、end依次循环输出。
如果synchronized (一个变量)
public void fun3() throws InterruptedException {
String num = "1";
synchronized (num){
System.out.println("3----start");
TimeUnit.SECONDS.sleep(3);
System.out.println("3----end");
}
}
结果:此时需要排队…
但是,如果这个num是参数传进来的呢?是否排队输出?
public static void main(String[] args) {
for (int i = 0;i<5;i++){
new Thread(()->{
try {
Data2 data2 = new Data2();
String s="A";
data2.fun3(s);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
class Data2{
public void fun3(String num) throws InterruptedException {
synchronized (num){
System.out.println("3----start");
TimeUnit.SECONDS.sleep(3);
System.out.println("3----end");
}
}
}
此时是需要排队输出,因为此时的String s=“A”;是常量池中拿出,只有一个。
如果传入的变量不是同一个呢?输出结果是什么样?
public static void main(String[] args) {
for (int i = 0;i<5;i++){
new Thread(()->{
try {
UUID uuid = UUID.randomUUID();
Data2 data2 = new Data2();
String s="asdasdasdasdasd"+uuid;
data2.fun3(s);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
答案:此时不需要排队,会先输出5个start,再输出5个end。因为此时每个a都是单独的对象。