多线程线程安全

博客主要围绕Java线程安全问题展开,介绍了三种解决方法,包括同步代码块、同步方法和显示锁Lock。还阐述了同步代码块和同步方法属于隐式锁,对比了显示锁和隐式锁的区别,如synchronized和Lock在性能、异常处理、响应中断等方面的不同。

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

线程安全问题

解决方法1:
线程安全1-同步代码块
格式:
synchronized(锁对象){
}

public class Demo_synchronized {
    public static void main(String[] args) {
        //Runnable r = new Ticket();
        Ticket r = new Ticket();//同一个任务
        new Thread(r).start();//多线程完成同一任务
        new Thread(r).start();
        new Thread(r).start();
    }
    static class Ticket implements Runnable{
        //票数
        private int count = 10;
        //注意所有线程只能有一把锁
        private Object o = new Object();//同一任务o只有一个
        @Override
        public void run() {
            while(true){
                //抢到该锁执行下列程序
                synchronized (o){
                    if(count>0){
                        //卖票
                        System.out.println("正在准备卖票");
                        //睡眠1s
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        count--;
                        System.out.println(Thread.currentThread().getName()+"余票"+count);
                    }else{
                        //没有余票则结束线程
                        return;
                    }
                }
            }
        }
    }
}

若没有锁住,可能会导致一个线程卖了一张票,还没有进行count–,另一线程进行操作,导致最后count可能出现负数
在这里插入图片描述
有锁之后,排队操作synchronized(锁对象){}中间的内容
在这里插入图片描述

解决方法2
线程安全2-同步方法

public class Demo_synchronized2 {
    public static void main(String[] args) {
        //一个任务
        Runnable r = new Ticket();
        //三个线程执行一个任务,锁对象是r
        new Thread(r).start();
        new Thread(r).start();
        new Thread(r).start();
    }
    static class Ticket implements Runnable{
        //票数
        private int count = 10;
        private Object o = new Object();
        @Override
        public void run() {
        	//private Object o = new Object();//若在此处创建o,代表每个线程会new一个o,看的不是同一把锁,就没有达到目的
            while(true){
                Boolean flag = sale();
                if(!flag){
                    break;
                }
            }
        }
        //同步方法,synchronized修饰方法,锁对象是this
        public synchronized Boolean sale(){
            //非静态对象 锁对象是this
            //静态对象 锁对象是Ticket.class
            //抢到该锁执行下列程序
            if(count>0){
                //卖票
                System.out.println("正在准备卖票");
                //睡眠1s
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println(Thread.currentThread().getName()+"余票"+count);
                return true;
            }else{
                //没有余票则结束线程
                return false;
            }
        }
    }
}

同步代码块和同步方法都属于隐式锁

解决方法3:
线程安全3-显示锁Lock
fair参数是true,表示是公平锁

static class Ticket implements Runnable{
        //票数
        private int count = 10;
        //ReentrantLock()是Lock接口的实现类
        //向上转型
        Lock l = new ReentrantLock();
        @Override
        public void run() {
            while(true){
                l.lock();
                //抢到该锁执行下列程序
                if(count>0){
                    //卖票
                    System.out.println("正在准备卖票");
                    //睡眠1s
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count--;
                    System.out.println(Thread.currentThread().getName()+"余票"+count);
                }else{
                    //没有余票则结束线程
                    return;
                }
                l.unlock();
            }
        }
    }

显示锁和隐式锁的区别:
链接: link.
synchronized是Java的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。JDK1.5以后引入了自旋锁、锁粗化、轻量级锁,偏向锁来有优化关键字的性能。

Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值