线程(二)之线程同步 死锁

本文介绍了Java中解决线程同步的三种方式:同步代码块、同步方法和Lock(ReentrantLock)。通过示例代码详细讲解了synchronized关键字的使用,包括同步代码块和同步方法,并对比了Lock接口实现的锁机制。总结指出Lock提供了更细粒度的锁控制,性能优于synchronized,并给出了Lock使用的基本步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、前言

解决线程同步问题有三种方式:同步代码块同步方法(JDK5新增)
使用synchronized 解决线程同步问题要时时刻刻注意要使用同一个同步监视器,特别是在继承创建多线程是要格外注意。

二、同步代码块

1、语法

synchronized(同步监视器){
    需要被同步的代码
}

2、对语法的说明

​ 需要被同步的代码就是操作共享数据的代码

​ 同步监视器可以是任何类的对象,但必须是唯一的

​ 实现创建多线程的案例中,通常用this作为同步监视器。继承创建多线程中,通常用 类名.class 充当同步监视器

3、代码演示

代码背景:创建两个窗口卖票,总票数是10张,通过实现Runnable接口创建多线程

public class TicketDome1 extends Thread {
   static int ticket = 10;//多个线程访问共享资源
   static Object obj = new Object();
      //注Object也要静态,因为俩个人公用一个钥匙

    @Override
    public void run() {
        //在run中模拟出所需任务
        while (true) {
        //为什么需要同步的代码,用同步代码块修饰,多个线程拥有一把锁,谁先获得,谁才可以进入,其他线程等待
        //当持有锁的线程把同步代码中内容执行完成后,离开同步代码块会自动释放锁
            synchronized (obj) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + ":" + ticket);
                    ticket--;
                } else
                    break;
            }
        }
    }
}
//测试类
public class Text {
    public static void main(String[] args) {
        TicketDome1 t1 = new TicketDome1();
        t1.setName("窗口1");
        t1.start();

        TicketDome1 t2 = new TicketDome1();
        t2.setName("窗口2");
        t2.start();
    }
}

4、总结

​ 这样处理可以做到线程安全,但是在同步代码块中线程是单线程执行,效率会降低

三、同步方法

1、语法

public synchronized void 方法名(){
    //操作共享数据的代码
}

2、对语法的说明

​ 同步方法仍然涉及到同步监视器,只是不需要我们显式的声明

​ 非静态的同步方法,同步监视器是this

​ 静态的同步方法,同步监视器是当前类本身

3、代码演示

public class TicketDome1 extends Thread {
    static int ticket = 10;//多个线程访问共享资源

    @Override
    public void run() {
        while (true) {
            if (ticket > 0) {
                printTicket();
            } else
                break;
        }
    }

    //用synchronized修饰方法,此方法为同步方法
    //锁对象默认为this,多个线程就有多把锁
    public static synchronized void printTicket() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + ":" + ticket);
            ticket--;
        }
    }
}

四、Lock方法

1、步骤

​ ① 实例化ReentrantLock对象

​ ② 在try块中开启锁

​ ③ 在finally块中关闭锁

2、代码演示

public class Ticket extends Thread {

    private static int ticket = 10;
    //实例化ReentrantLock对象
    private static ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                //开启锁
                lock.lock();
                if (ticket > 0) {
                    System.out.println(getName() + "票号为:" + ticket);
                    ticket--;
                } else {
                    break;
                }
            } finally {
                //关闭锁
                lock.unlock();
            }

        }
    }
}

五、总结

synchronized和Lock的区别

  • Lock是显式锁(手动开启和关闭锁);而synchronized是隐式锁,出了作用域自动释放
  • Lock只能作用于代码块;而sychronized可以作用于代码块也可以作用于方法
  • Lock锁,JVM花费较少时间,性能更好,锁的粒度更小,更有针对性

线程同步机制中优先使用顺序:Lock、同步代码块、同步方法;即锁的粒度越小越好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值