首页 > 其他分享 >多线程锁

多线程锁

时间:2023-11-12 23:36:00浏览次数:40  
标签:Thread synchronized lock 线程 ------ new 多线程

常见锁介绍

synchronized锁的八中情况

package com.shaonian.juc.more_thread_lock;

import java.util.concurrent.TimeUnit;

class Phone {

    public static synchronized void sendSMS() throws Exception {
        //停留4秒
        TimeUnit.SECONDS.sleep(4);
        System.out.println("------sendSMS");
    }

    public synchronized void sendEmail() throws Exception {
        System.out.println("------sendEmail");
    }

    public void getHello() {
        System.out.println("------getHello");
    }
}

/**
 * @Description: 8锁
 *
1 标准访问,先打印短信还是邮件
------sendSMS
------sendEmail

2 停4秒在短信方法内,先打印短信还是邮件
------sendSMS
------sendEmail

3 新增普通的hello方法,是先打短信还是hello
------getHello
------sendSMS

4 现在有两部手机,先打印短信还是邮件
------sendEmail
------sendSMS

5 两个静态同步方法,1部手机,先打印短信还是邮件
------sendSMS
------sendEmail

6 两个静态同步方法,2部手机,先打印短信还是邮件
------sendSMS
------sendEmail

7 1个静态同步方法,1个普通同步方法,1部手机,先打印短信还是邮件
------sendEmail
------sendSMS

8 1个静态同步方法,1个普通同步方法,2部手机,先打印短信还是邮件
------sendEmail
------sendSMS

 */

public class Lock8QuestionBySynchronized {
    public static void main(String[] args) throws Exception {

        Phone phone = new Phone();
        Phone phone2 = new Phone();

        new Thread(() -> {
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "AA").start();

        Thread.sleep(100);

        new Thread(() -> {
            try {
                // phone.sendEmail();
                // phone.getHello();
                phone2.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "BB").start();
    }
}

代码结果原因分析,见博客中synchronized关键字回顾。

ReentrantLock读写锁分析

/**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();//默认是非公平锁
    }

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {//传入false,定义的就是非公平的读写锁
        sync = fair ? new FairSync() : new NonfairSync();
    }
非公平锁(ReentrantLock实现)

非公平锁是多个线程加锁时直接尝试获取锁,能抢到锁到直接占有锁,抢不到才会到等待队列的队尾等待。确定可能会出现线程饿死现象(锁一直被一个线程持有,某些线程一直拿不到锁),优点是执行效率高,可以直接获取锁。

static final class NonfairSync extends Sync {//ReentrantLock中的静态内部类
	private static final long serialVersionUID = 7316153563782823691L;

/**
 * Performs lock.  Try immediate barge, backing up to normal
 * acquire on failure.
 */
    final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}
公平锁(ReentrantLock实现)

公平锁是指多个线程按照申请锁的顺序来获取锁,线程直接进入队列中排队,队列中的第一个线程才能获得锁。保证每个线程都能拿到锁,优点是执行效率比非公平锁低,优点是不会出现线程饿死现象。

static final class FairSync extends Sync {
    private static final long serialVersionUID = -3000897897090466540L;

    final void lock() {
        acquire(1);
    }

    /**
     * Fair version of tryAcquire.  Don't grant access unless
     * recursive call or no waiters or is first.
     */
    protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            if (!hasQueuedPredecessors() &&
                compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;
            if (nextc < 0)
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
}

可重入锁(ReentrantLock实现)

synchronized(隐式)和Lock(显式)都是可重入锁,也叫递归锁。特点,类似于,有了第一把锁,此锁内部锁的代码都可以访问。像开了大门,开剩下的门就不用再用钥匙开门了。

/**
 * @author 长名06
 * @version 1.0
 * 可重入锁案例
 */
public class ReentrantLockDemo {

    private synchronized void add(){
        add();
    }


    public static void main(String[] args) {

        //new ReentrantLockDemo().add();//会出现StackOverflowError

        Object o = new Object();

        new Thread(() -> {
            synchronized (o){
                System.out.println(Thread.currentThread().getName() + "外部");
                synchronized (o){
                    System.out.println(Thread.currentThread().getName() + "中部");
                    synchronized (o){
                        System.out.println(Thread.currentThread().getName() + "内部");
                    }
                }
            }
        },"aa").start();
        
        ReentrantLock lock = new ReentrantLock();
        new Thread(() -> {
            try{
                lock.lock();
                System.out.println(Thread.currentThread().getName() + "外层操作");
                try{
                    lock.lock();
                    System.out.println(Thread.currentThread().getName() + "内层操作");

                }finally {
                    lock.unlock();
                }
            }finally {
                lock.unlock();
            }
        }).start();
     //结果
     //Thread-0外层操作
     //Thread-0内层操作
    }
}

死锁

基本介绍

死锁,是一种多个线程在执行过程中,因竞争资源时,导致线程互相持有其他线程执行需要的锁,从而引起线程等待的现象。在没有外力的作用下,程序会崩溃。

引起死锁的原因
  • 1.系统资源不足。
  • 2.进程运行顺序不合适。
  • 3.资源分配不当。
/**
 * @author 长名06
 * @version 1.0
 * 死锁代码
 */
public class DeadLock {

    static Object a = new Object();
    static Object b = new Object();
    public static void main(String[] args) {

        new Thread(() -> {
            synchronized (a){
                System.out.println(Thread.currentThread().getName() + "持有锁a,试图后去锁b");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (b){
                    System.out.println(Thread.currentThread().getName() + "获取锁b");
                }
            }
        },"a").start();

        new Thread(() -> {
            synchronized (b){
                System.out.println(Thread.currentThread().getName() + "持有锁b,试图后去锁a");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (a){
                    System.out.println(Thread.currentThread().getName() + "获取锁a");
                }
            }
        },"b").start();
    }
}
验证线程一直等待是否是死锁
  • 1.jps -l 命令类似linux下的ps - ef 可以查询java的线程

    正在执行的死锁代码的进程id
  • 2.jstack工具(JVM 自带的堆栈工具) jstack 线程id 可以查询对应线程的信息
    执行jstack pid指令
    提示语句中会有 Found 1 deadlock

只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。

标签:Thread,synchronized,lock,线程,------,new,多线程
From: https://www.cnblogs.com/changming06/p/17828062.html

相关文章

  • 【.NET】多线程:自动重置事件与手动重置事件的区别
    在多线程编程中,如果每个线程的运行不是完全独立的。那么,一个线程执行到某个时刻需要知道其他线程发生了什么。嗯,这就是所谓线程同步。同步事件对象(XXXEvent)有两种行为:1、等待。线程在此时会暂停运行,等待其他线程发出信号才继续(等你约);2、发出信号。当前线程发出信号,其他正在等待......
  • Redis6.0使用多线程是怎么回事?
    Redis不是说用单线程的吗?怎么6.0成了多线程的?Redis6.0的多线程是用多线程来处理数据的读写和协议解析,但是Redis执行命令还是单线程的。这样做的⽬的是因为Redis的性能瓶颈在于⽹络IO⽽⾮CPU,使⽤多线程能提升IO读写的效率,从⽽整体提⾼Redis的性能。为什么命令执行为什么不采用多线......
  • 如何解决多线程下的共享对象问题?分布式系统又该如何应对?
    嗨,各位小米粉丝们!欢迎来到小米带你飞的微信公众号!今天我们要聊的话题可是程序员们都头疼的大问题哦——多线程情况下的对象共用问题,以及在分布式系统中的应对策略!小米要给大家详细解读一下,让你的技术面试不再被问倒!多线程中,如何解决对象共用问题?首先,我们得先了解多线程带来的挑战。......
  • java怎么实现对指定进行多线程访问的效果
    要使用Java实现对特定网站(例如"http://xkrj5.com")的多线程访问,你可以采用以下步骤:创建一个线程类:这个类将负责执行HTTP请求。使用线程池:这可以更有效地管理多个线程。执行HTTP请求:使用Java的网络库(如 HttpURLConnection 或第三方库如ApacheHttpClient)。下面是......
  • C++11 并发编程基础(一):并发、并行与C++多线程
    C++11标准在标准库中为多线程提供了组件,这意味着使用C++编写与平台无关的多线程程序成为可能,而C++程序的可移植性也得到了有力的保证。另外,并发编程可提高应用的性能,这对对性能锱铢必较的C++程序员来说是值得关注的。1.何为并发并发指的是两个或多个独立的活动在同一时段内发生......
  • 十、Java多线程
    一、多线程概述1、进程:正在运行的程序,是系统进行资源分配和调用的独立单位。每一个进程都有它自己的内存空间和系统资源。2、线程:是进程中的单个顺序控制流,是一条执行路径一个进程如果只有一条执行路径,则称为单线程程序。一个进程如果有多条执行路径,则称为多线程程序。3......
  • 实验:C SOCKET 多线程服务端链表分组实现聊天室
    目录......
  • Scala中编写多线程爬虫程序并做可视化处理
    在Scala中编写一个爬虫程序来爬取店铺商品并进行可视化处理,需要使用Selenium和Jsoup库来操作网页。在这个例子中,我们将使用多线程来提高爬取速度。1、首先,我们需要引入所需的库:importorg.openqa.selenium.Byimportorg.openqa.selenium.WebDriverimportorg.openqa.selenium.Web......
  • Python进行多线程爬取数据通用模板
    首先,我们需要导入所需的库,包括requests和BeautifulSoup。requests库用于发送HTTP请求,BeautifulSoup库用于解析HTML文档。importrequestsfrombs4importBeautifulSoup然后,我们需要定义一个函数来发送HTTP请求并返回响应。在这个函数中,我们使用requests库的get方法来发送一个GET......
  • js怎么实现对某个网址进行多线程get访问,实现压力测试效果
    在JavaScript中,实际上没有传统意义上的"多线程",但是我们可以使用WebWorkers来模拟多线程行为。WebWorkers允许您运行JavaScript操作在后台线程,不会影响主线程的性能。然而,WebWorkers更多用于在浏览器端执行耗时的计算任务,并不适用于执行HTTP请求。 对于Node.js环境,我们可以......