synsynchronized的使用方法:
1、synchronized修饰方法
(1)synchronized修饰非静态方法: 锁的是方法的调用者
import java.util.concurrent.TimeUnit;
class Data {
/*synchronized修饰非静态方法,锁的是即方法的调用者,即
调用func1方法的对象*/
public synchronized void func1() {
try {
TimeUnit.SECONDS.sleep(3);//休眠3秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("1....");
}
public synchronized void func2() {
System.out.println("2....");
}
}
Test1:
public class Test1 {
public static void main(String[] args) {
Data data=new Data();
new Thread(()->{
data.func1();
}).start();
new Thread(()->{
data.func2();
}).start();
}
}
结果为:
在上面的代码中,由于synchronized修饰非静态方法:,锁的是方法的调用者;
所以 在本代码中锁的是Data类的对象,不同的Data对象,有不同的锁,但是此代码中只有一个data对象,第一个线程执行的是data.fun1()方法,第二个线程执行的是data.fun2()方法;
所以当第一个线程执行data.fun1()方法,获取到data对象的锁之后,执行data.fun1()方法,第二个线程获取不到data对象的锁,所以第二个线程中的方法data.fun2()方法无法执行;只有当第一个线程执行完毕(data.fun1()方法执行完),释放了data锁之后,第二个线程才能获取到data的锁,执行data.fun2()方法;
Test2:
public class Test1 {
public static void main(String[] args) {
Data data = new Data();
Data data2 = new Data();
new Thread(() -> {
data.func1();
}).start();
new Thread(() -> {
data2.func2();
}).start();
}
}
结果为:
在上面的代码中,由于synchronized修饰非静态方法:,锁的是方法的调用者;
所以锁的是Data类的对象,不同的Data对象,有不同的锁,此代码中有两个Data对象:data,data2;
所以当第一个线程获取到data对象的锁之后,执行data.fun1()方法;第二个线程执行的是data2.fun2()方法,其与第一个线程获取的不是同一个对象的锁,所以也能与第一个线程同时执行,但fun1()方法中,线程休眠了3秒,所以结果先输出2,再输出1;
(2)synchronized修饰静态方法:锁的是class本身
class Data2 {
/*synchronized修饰静态方法,锁的是class本身,本代码中
锁的是Data2这个类本身,锁定的不是对象*/
public synchronized static void func1() {
try {
TimeUnit.SECONDS.sleep(3);//休眠3秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("1....");
}
public synchronized static void func2() {
System.out.println("2....");
}
}
Test1:
public class Test2 {
public static void main(String[] args) {
Data2 data1=new Data2();
new Thread(()->{
data1.func1();
}).start();
new Thread(()->{
data1.func2();
}).start();
}
}
结果为:
上面的代码中,由于synchronized修饰静态方,:锁的是class本身;
所以第一个线程执行data1.func1()方法,获取到了Data类的锁;而第二个线程中执行的方法是data1.func2()方法,但因为第一个线程已经获取了Data类的锁,所以无法获取锁,只有当第一个线程执行完data1.func1()方法之后,释放了Data类的锁,第二个线程才能运行执行获取到Data类的锁,执行data1.func2()方法;
Test2:
public class Test2 {
public static void main(String[] args) {
Data2 data1=new Data2();
Data2 data2=new Data2();
new Thread(()->{
data1.func1();
}).start();
new Thread(()->{
data2.func2();
}).start();
}
}
结果为:
在上面的代码中,synchronized修饰的是静态方法(static修饰的方法),则锁的是class本身;
所以在本代码中,锁的是Data.class这个类对象,由于一个类只有一个class对象,所以不管该类有几个实例对象,当一个线程获取该类的锁之后,其他线程就无法获取该类的锁了,只有当上一个线程释放了锁之后,其他线程才能获取这个类的锁,执行方法
2、synchronized修饰代码块
(1)synchronized(类对象)即synchronized(class):锁的是同一个类
class Data3{
public void func1(Integer num) {
synchronized (Data3.class) {//锁的是同一个类
System.out.println("start....");
try {
TimeUnit.SECONDS.sleep(3);//休眠3秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end....");
}
}
}
Test:
import java.util.concurrent.TimeUnit;
public class Test3 {
public static void main(String[] args) {
Data3 data=new Data3();
for(int i=0;i<5;i++){
Integer num=Integer.valueOf(i);
new Thread(()->{
data.func1(num);
}).start();
}
}
}
由于代码中 synchronized (Data3.class)锁的是Data3.class这个类对象,
所以对于代码中的那5个线程,每次执行fun1(num)方法时,只有当一个线程获取到Data3.class这个类的锁之后,执行完func1(num)方法,释放了Data3.class的锁之后,才能执行下一个线程;
(2)synchronized(对象):锁的是同一个对象
class Data3{
public void func2(Integer num) {
synchronized (num) {//锁的是同一个num对象
System.out.println(num+"start....");
try {
TimeUnit.SECONDS.sleep(3);//休眠3秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("end....");
}
}
}
Test:
import java.util.concurrent.TimeUnit;
public class Test3 {
public static void main(String[] args) {
Data3 data=new Data3();
for(int i=0;i<5;i++){
Integer num=Integer.valueOf(1);//同一个num对象
new Thread(()->{
data.func2(num);
}).start();
}
}
}
由于代码中 synchronized (num)锁的是num这个实例对象;
又由于 Integer num=Integer.valueOf(1),不管创建多少次,都是对应的堆中的同一个对象,
所以对于代码中的那5个线程,每次执行fun2(num)方法时,锁的时同一个num,只有当一个线程获取到num这个对象的锁之后,执行完func2(num)方法,释放了num的锁之后,才能执行下一个线程;
Test3:
public class Test3 {
public static void main(String[] args) {
Data3 data=new Data3();
for(int i=0;i<5;i++){
Integer num=Integer.valueOf(i);//不同的num对象
new Thread(()->{
data.func2(num);
}).start();
}
}
}
结果为:
由于代码中 synchronized (num)锁的是num这个实例对象;
又由于 Integer num=Integer.valueOf(i),这5次创建过程中,对应的是不同的num实例对象;
所以对于代码中的那5个线程,每次执行fun2(num)方法时,锁的都不是同一个num的锁,他们互不影响,所以5个线程同时执行;