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睡醒之后结束的,这就说明不同锁线程之间是不会相互争夺的,所以也就不会阻塞。

总结

最后我们来总结一下本节的内容,本节演示了多个线程争夺同一把锁和不同锁的情况,发现争夺同一把锁时线程会阻塞,争夺不同锁时,线程不会阻塞。 

 

posted @ 2022-05-03 14:51  小陈子博客  阅读(53)  评论(0)    收藏  举报