16.同一把锁
同一把锁
引言
本节给大家演示一下,多个线程争夺同一把锁和不同锁的场景。
同一把锁
首先自定义一个任务,任务内容就是两个线程分别去执行两个不同的同步代码块,如何做到这一点?我们可以定义一个Boolean类型的标记,然后通过标记来切换不同线程去执行不同的代码块。所以这里我们还要定义一个更改标记的方法用于切换标记,接着在run方法中判断标记,先来编写if语句,也就是当标记为处时,在里面写上同步大模块,同步锁为task.class,同步内容就是使当前线程休眠三秒钟,目的是拿着锁三秒钟不放,看看另一个争夺锁的线程会不会等待,睡醒以后打印当前线程名称加睡醒了。
接下来编写else一句,也就是当标记为false时,写上同步所也为task.class的同步代码块,同步内容就是输出当前线程名称和一句话。
Task
package com.chenjie.executor.day16; /** * packageName com.chenjie.executor.day14 * * @author chenjie * @version JDK 8 * @className TicketTask (此处以class为例) * @date 2024/5/28 * @description TODO */ public class Task implements Runnable { private boolean flag = true; public void setFlag(boolean flag) { this.flag = flag; } @Override public void run() { if (flag) { synchronized (Task.class) { try { Thread.sleep(3000L); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(Thread.currentThread().getName()+":睡醒了"); } } else { synchronized (Task.class) { System.out.println(Thread.currentThread().getName()+":人人都是程序员"); } } } }
main
下面我们来执行这个任务,首先将任务创建出来,然后创建两个线程,让他们去争夺同一把锁,接着将任务分别传递给他们。这里我们先启动thread1,待会再启动thread2,因为在启动thread2之前,需要切换一次标记,达到不同线程执行不同代码块的目的。我们让主线程休眠一秒钟一秒钟之后去切换这个标记,使用try---catch捕获sleep方法抛出的异常。
接着设置标记为false,因为标记的处时值为true,所以切换过后就是false。最后启动thread2。下面来看看运行结果,
package com.chenjie.executor.day16; /** * packageName com.chenjie.executor.day09 * * @author chenjie * @version JDK 8 * @className Main1 (此处以class为例) * @date 2024/5/27 * @description TODO */ public class Main { /** * 创建三个线程来跑这段代码 * @param args */ public static void main(String[] args) { Task task=new Task(); Thread thread = new Thread(task,"thread"); Thread thread1 = new Thread(task,"thread1"); thread.start(); try { Thread.sleep(1000L); } catch (InterruptedException e) { throw new RuntimeException(e); } task.setFlag(false); thread1.start(); } }
结果
thread:睡醒了 thread1:人人都是程序员 进程已结束,退出代码为 0
这里说明一下结果中的thread就是thread对象,所谓的thread1就是所谓的thread1对象。好了,从运行结果来看,两个线程的确是在争夺同1把所, thread拿着锁休眠了三秒钟,thread1在thread睡醒之后输出内容。
这就说明thread拿着锁休眠的时候,thread1被阻塞了。他在等thread0释放锁。同时也说明,当线程拿着锁休眠时,是不会释放锁的。
不同锁
以上就是同一把所的情况。下面我们再来看看不同锁的情况,修改任务代码,将else语句中的同步锁换成main.class,看看执行结果会怎么样。
task
package com.chenjie.executor.day16; /** * packageName com.chenjie.executor.day14 * * @author chenjie * @version JDK 8 * @className TicketTask (此处以class为例) * @date 2024/5/28 * @description TODO */ public class Task implements Runnable { private boolean flag = true; public void setFlag(boolean flag) { this.flag = flag; } @Override public void run() { if (flag) { synchronized (Task.class) { try { Thread.sleep(3000L); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(Thread.currentThread().getName()+":睡醒了"); } } else { synchronized (Main.class) { System.out.println(Thread.currentThread().getName()+":人人都是程序员"); } } } }
结果
thread1:人人都是程序员 thread:睡醒了 进程已结束,退出代码为 0
从运行结果来看,thread1还没等thread睡醒就已经打印了内容,整个程序是在thread睡醒之后结束的,这就说明不同锁线程之间是不会相互争夺的,所以也就不会阻塞。
总结
最后我们来总结一下本节的内容,本节演示了多个线程争夺同一把锁和不同锁的情况,发现争夺同一把锁时线程会阻塞,争夺不同锁时,线程不会阻塞。
本文来自博客园,作者:小陈子博客,转载请注明原文链接:https://www.cnblogs.com/cj8357475/p/16086037.html

浙公网安备 33010602011771号