欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

多线程的安全性问题

程序员文章站 2022-03-09 23:19:21
...

上一节中,虽然我们已经完成了卖票程序,但是其实隐藏了一个非常严重的安全问题,我们看代码这段代码:

class Ticket implements Runnable{
    private  int tick=100;
    public void run(){
        while (true){ 
            if(tick>0){   System.out.println(Thread.currentThread().getName()+"....sale"+tick--);

            }
        }
    }
}

当票剩余一张时,在我们的if(tick>0)的时候,我们的0线程进入,这时候0线程进入暂时状态,1线程进入,因为此时tick还未变化, 如果这个时候1线程也进入暂时状态。这个时候就会出现卖出0张票和-1张票的情况。

我们可以模拟下这个情况:

class Ticket implements Runnable{
    private  int tick=100;
    public void run(){
        while (true){ 
            if(tick>0){
            try{
                 Thread.sleep(100);   
                }catch(Exception e){

                }
            }
           System.out.println(Thread.currentThread().getName()+"....sale"+tick--);

            }
        }
    }
}

此时我们运行发现:
多线程的安全性问题

多线程的运行出了安全问题。
当多个线程在操作同一个共享数据时, 一个线程对多余语句只执行了一部分,还没执行完,另一个线程参与进来执行,导致共享数据的错误。

解决办法: 对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不可以参与执行。
java对于多线的安全问题提供了专业的解决方式, 就是同步代码块。

synchronized(对象)
{
    需要同步的代码块
}

改正后的代码

class Ticket implements Runnable {
    private int tick = 100;
    Object o=new Object(); //锁
    public void run() {
        while (true) {
            synchronized (o) {
                if (tick > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "....sale" + tick--);
                }
            }
        }
    }
}

原理,锁对象具有一个标志位,当线程进来时,将标志位置成0,其他线程进不来,出去后,标志位重新置成1,其他线程就可以进来了。
对象如同锁,持有锁的线程可以在同步中执行,没有持有锁的线程即使获取了cup的执行权,也进不去, 因为没有获取锁。

同步的前提:
1.必须要有两个或者两个以上的线程。
2.必须是多个线程使用同一个锁。
必须保证同步中只有一个线程在运行。
好处:解决了多线程的安全问题;
弊端:多个线程需要判断锁,较为消耗资源。

同步函数:
我们可以让函数具有同步的功能,只需要在定义函数的时候加上synchronized,此时该函数就具备同步代码块的功能,线程安全。

public synchronized void add (int n){
    sum=sum+n;
}

同步函数用的是哪一个锁呢?
函数需要被对象调用,那么函数都有一个所属对象引用,就是this。所以同步函数使用的锁是this。