美文网首页
java解决多线程安全的方式

java解决多线程安全的方式

作者: eliteTyc | 来源:发表于2020-03-06 14:05 被阅读0次

解决多线程安全问题的方式(加锁)包含以下几种:

synchronized关键字:又包含同步代码块,同步方法

Lock锁:

锁的分类: 类锁(class锁),对象锁

实例:现有如下代码,总共100张票,3个窗口同时售卖,这里采用实现Runnable接口的方式,还可以使用继承Thread方式实现,Runnable与Thread类详解

public class RunnableWindowTest{
    public static void main(String[] args) {
        RunnableWindow runnableWindow = new RunnableWindow();
        new Thread(runnableWindow,"窗口1").start();
        new Thread(runnableWindow,"窗口2").start();
        new Thread(runnableWindow,"窗口3").start();

    }
}
class RunnableWindow implements Runnable {
    private int ticket=100;

    @Override
    public void run() {
            while (true){
                if (ticket>0){
                    System.out.println(Thread.currentThread().getName()+":卖出票号"+ticket);
                    ticket--;
//                    睡眠100毫秒凸显问题
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    break;
                }
            }
    }
    
}

出现的问题,运行时,会出现重票,错票的问题,可以明显看到下图,出现很多重票,同时很多票号也不见了,例如11号票

image.png

解决方案

synchronized关键字之-同步代码块

同步代码快之类锁方式实现线程安全:使用synchronized包裹if-else块,如果直接锁住while循环,会导致第一个进去的线程一直抢占cpu资源,虽然票号正确,但是所有票都是同一个窗口卖出

class RunnableWindow implements Runnable {

    private int ticket = 100;

    @Override
    public void run() {

        while (true) {
          // 新加行,synchronized (RunnableWindow.class)表示锁住当前类,synchronized (this)指代当前类的实例对象
            //synchronized (this){
            synchronized (RunnableWindow.class) {
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + ":卖出票号" + ticket);
                    ticket--;
//                    睡眠100毫秒凸显问题
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    break;
                }
            }
        }
    }

}

同步代码块之对象锁方式实现线程安全

class RunnableWindow implements Runnable {

    private int ticket = 100;
        // 新加行,创建一个object对象
    private Object obj = new Object();

    @Override
    public void run() {

        while (true) {
          // 新加行,使用对象来锁住当前代码块
            synchronized (obj) {
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + ":卖出票号" + ticket);
                    ticket--;
//                    睡眠100毫秒凸显问题
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    break;
                }
            }
        }
    }

}

synchronized关键字之-同步方法

同步方法之对象锁方式实现线程安全:synchronized关键字修饰的非静态方法,表示当锁为当前类对象实例,如果修饰的为静态方法,则表示锁为当前类,为类锁

class RunnableWindow implements Runnable {

    private int ticket = 100;

    @Override
    public void run() {

        while (true) {
//            新加行调用同步方法
            getTicket();
//            循环判断票数是否小于等于0,是则跳出循环
            if (ticket<=0){
                break;
            }

        }
    }
//  synchronized关键字修饰方法,实现同步方法
    private synchronized void getTicket(){
        if (ticket > 0) {
            System.out.println(Thread.currentThread().getName() + ":卖出票号" + ticket);
            ticket--;
//                    睡眠100毫秒凸显问题
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

Lock锁方式:lock()与unlock()方法之间的代码为同步代码块,每次只允许一个线程进入

class RunnableWindow implements Runnable {

    private int ticket = 100;

    //    新建一个ReentrantLock实例
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {

        while (true) {
            try {
//                新加行
                lock.lock();
                if (ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + ":卖出票号" + ticket);
                    ticket--;
//                    睡眠100毫秒凸显问题
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    break;
                }
            } finally {
//                新加行
                lock.unlock();
            }

        }
    }

}

image.png

相关文章

网友评论

      本文标题:java解决多线程安全的方式

      本文链接:https://www.haomeiwen.com/subject/vufvrhtx.html