1.Synchronized
Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。当两个并发线程访问同一个对象object中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线程访问object的一个加锁代码块时,另一个线程仍可以访问该object中的非加锁代码块。
/**
* @author EAST
* @version 系统项目版本
* @since JDK 1.8
* 2023/5/25 8:35
* 测试Synchronized关键字
*/
class SynchronizedTest {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread() {
public void run() {
//调用method1
SynchronizedTest.method1();
}
};
t1.setName("第一个线程");
t1.start();
//保证第一个线程先调用method1
Thread.sleep(1000);
Thread t2 = new Thread() {
public void run() {
//调用method2
SynchronizedTest.method2();
}
};
t2.setName("第二个线程");
t2.start();
Thread t3 = new Thread() {
public void run() {
//调用method2
SynchronizedTest.method3();
}
};
t3.setName("第三个线程调皮闯入");
t3.start();
}
public static void method1() {
synchronized (SynchronizedTest.class) {
System.out.println(Thread.currentThread().getName() + " 进入了method1方法");
try {
System.out.println("运行15秒");
Thread.sleep(15000);
System.out.println("method1方法结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static synchronized void method2() {
// 就无法进入method2,推断出,method2的同步对象,就是TestReflection.class
System.out.println(Thread.currentThread().getName() + " 进入了method2方法");
try {
System.out.println("运行3秒");
Thread.sleep(3000);
System.out.println("method2方法结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void method3() {
// 就无法进入method2,推断出,method2的同步对象,就是TestReflection.class
System.out.println(Thread.currentThread().getName() + " 进入了method3方法");
try {
System.out.println("嘤嘤嘤~~~没加synchronized,我在这里捣乱3秒");
Thread.sleep(3000);
System.out.println("method3方法结束,拜拜~");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
1.1Synchronized关键字使用方法
在上面的代码中可以看到Synchronized关键字的两种使用方法
public static void method1() {
synchronized (SynchronizedTest.class) {
System.out.println(Thread.currentThread().getName() + " 进入了method1方法");
try {
System.out.println("运行15秒");
Thread.sleep(15000);
System.out.println("method1方法结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static synchronized void method2() {
System.out.println(Thread.currentThread().getName() + " 进入了method2方法");
try {
System.out.println("运行3秒");
Thread.sleep(3000);
System.out.println("method2方法结束");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
可以在方法中用Synchronized关键字给method1添加同步对象SynchronizedTest.class,只有占用SynchronizedTest.class才可以执行到这里,在程序一开始我们使用线程执行了method1(),在休眠1s后执行method2()。在实际运行时,method1()的执行过程当中(15s线程)的第一秒(休眠的1s),就执行了method2(),具体如下图

当然也可以在方法的返回值和权限符之间使用Synchronized关键字,给method2添加同步对象SynchronizedTest.class,这样的话method1()和method2()就是同步方法,在执行过程中,由于SynchronizedTest.class的占用(相当于加锁),导致method1和method2两个方法不能并发执行,也就是说这两个方法是同步关系,按照顺序依次执行,method3方法没有加Synchronized关键字,因此可以在执行过程中并发插队。
最后结果:method1执行(0-1s)——>method2执行完毕(1s-4s)——>method1结束(4s-15s)——>method3开始(15s)——>method3结束(18s)
public static void method3() {
System.out.println(Thread.currentThread().getName() + " 进入了method3方法");
try {
System.out.println("嘤嘤嘤~~~没加synchronized,我在这里捣乱3秒");
Thread.sleep(3000);
System.out.println("method3方法结束,拜拜~");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
2.线程安全的类
假如说一个类中,所有的方法都是由Synchronized关键字所修饰,那么这个类就可以说是线程安全的类
本文介绍了Java中的Synchronized关键字,用于实现线程同步。通过一个示例展示了synchronized在方法和代码块上的使用,以及其对并发执行的影响。方法1和方法2是同步的,它们按顺序执行,而未加锁的方法3则可以并发插入。一个类如果所有方法都同步,则称其为线程安全的类。

1869





