在并发编程中,锁现象通常指的是多线程情况下可能出现的一些特定问题或现象。以下是八种常见的并发编程中的锁现象:
package org.example.lock8;
import java.util.concurrent.TimeUnit;
public class Test1 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone{
public synchronized void sendSms() {
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}
结果
发短信
打电话
这种情况,等待4秒后,先输出发短信,后输出打电话,而不是先输出打电话
为什么是先发短信,而不是先打电话呢
原因是因为先调用发短信的方法吗。不对,原因是因为synchronized锁的对象是方法的调用者(发短信和打电话这两个方法,都使用了synchronized),而且这两个方法都被phone所调用,由于这两个方法使用的是同一把锁,所以谁先拿到锁,谁先执行
看看先打印什么出来
package org.example.lock8;
import java.util.concurrent.TimeUnit;
public class Test2 {
public static void main(String[] args) {
Phone2 phone = new Phone2();
new Thread(()->{
phone.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.hello();
},"B").start();
}
}
class Phone2{
public synchronized void sendSms() {
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
public void hello() {
System.out.println("hello");
}
}
结果
hello
发短信
因为这种情况下hello方法 没有加锁,不是同步方法,不受锁的影响
package org.example.lock8;
import java.util.concurrent.TimeUnit;
public class Test2 {
public static void main(String[] args) {
Phone2 phone1 = new Phone2();
Phone2 phone2 = new Phone2();
new Thread(()->{
phone1.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone2{
public synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}
结果
打电话
发短信
原因:现在有两个对象,两个调用者,即有两把锁,由于发短信方法 延迟了4秒钟(TimeUnit.SECONDS.sleep(4)😉,所以phone2先拿到锁,所以先执行 打电话
其实就是在方法上加上static,变为静态方法
package org.example.lock8;
import java.util.concurrent.TimeUnit;
public class Test3 {
public static void main(String[] args) {
Phone3 phone = new Phone3();
new Thread(()->{
phone.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone3{
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call() {
System.out.println("打电话");
}
}
结果
发短信
打电话
为什么是先发短息,这个static有什么影响吗
static是静态方法,类一加载就有了,那么锁的是class,是一个模板,发短信和打电话这两个方法的本质都是phone3,phone3只有唯一的class对象,这个class全局唯一,这两个方法都被static修饰了,所以这两个方法使用的是同一个锁
package org.example.lock8;
import java.util.concurrent.TimeUnit;
public class Test3 {
public static void main(String[] args) {
Phone3 phone1 = new Phone3();
Phone3 phone2 = new Phone3();
new Thread(()->{
phone1.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone3{
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public static synchronized void call() {
System.out.println("打电话");
}
}
结果
发短信
打电话
如果它是一个普通的synchronized方法,它是由调用者对象来操作它
但是现在加上了static
这个锁 锁的的class对象
这个phone3的两个对象的class类模板只有一个,锁的是class,这个class全局唯一,这两个方法都被static修饰了,所以这两个方法使用的是同一个锁
package org.example.lock8;
import java.util.concurrent.TimeUnit;
public class Test4 {
public static void main(String[] args) {
Phone4 phone = new Phone4();
new Thread(()->{
phone.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone.call();
},"B").start();
}
}
class Phone4{
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}
结果
打电话
发短信
原因:静态同步方法锁的是class类模板
普通同步方法锁的是调用者
这里有两把锁,这两个方法用的不是同一把锁,所以先执行打电话,后执行发短信,发短信要延后4秒(TimeUnit.SECONDS.sleep(4)😉
package org.example.lock8;
import java.util.concurrent.TimeUnit;
public class Test4 {
public static void main(String[] args) {
Phone4 phone1 = new Phone4();
Phone4 phone2 = new Phone4();
new Thread(()->{
phone1.sendSms();
},"A").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
phone2.call();
},"B").start();
}
}
class Phone4{
public static synchronized void sendSms() {
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("发短信");
}
public synchronized void call() {
System.out.println("打电话");
}
}
结果
打电话
发短信
同理,这里有2个锁,和第七个的情况一样
在技术的道路上,我们不断探索、不断前行,不断面对挑战、不断突破自我。科技的发展改变着世界,而我们作为技术人员,也在这个过程中书写着自己的篇章。让我们携手并进,共同努力,开创美好的未来!愿我们在科技的征途上不断奋进,创造出更加美好、更加智能的明天!