多线程——安全问题

来源:互联网 发布:陈欣怡药检呈阳性知乎 编辑:程序博客网 时间:2024/06/07 20:26

多线程运行可能出现安全问题

 

以买票程序为例,共有100张票,四个窗口同时买票。

class Ticket implements Runnable{private int tick = 100;public void run(){while(true){if(tick > 0){try{Thread.sleep(10);}catch(Exception e){}System.out.println(Thread.currentThread().getName() + "  sale.." + tick--);}}}}public class Example1 {public static void main(String[] args){Ticket t = new Ticket();Thread t1 = new Thread(t);Thread t2 = new Thread(t);Thread t3 = new Thread(t);Thread t4 = new Thread(t);t1.start();t2.start();t3.start();t4.start();}}

通过分析,发现打印出0-1-2等错票。

多线程的运行出现了安全问题。

造成这种结果的可能原因:

tick = 1的时候,0线程进来,执行sleep方法,进入睡眠状态。1线程进来,也进入睡眠。2线程进来,进入睡眠。3线程进来,执行输出语句,tick--变成0.这时1线程醒来直接执行输出语句,不需要判断,因为之前已经判断过。输出02线程也醒了,输出-1.于是就出现了输出负数的情况。


问题的原因:

当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据的错误

 

解决办法:

对多条操作共享数据的语句,让一个线程都执行完。在执行过程中,其他线程不可 以参与执行

 

Java对于多线程的安全问题提供了专业的解决方式:

同步代码块

Synchronized(对象)

{

需要同步的代码 //哪些语句在操作共享数据,哪些代码就需要同步

}

对象如同锁,持有锁的线程可以在同步中执行。

没有持有锁的线程即使获取CPU的执行权,也进不去。

对象有一个标志值,用来标志锁是打开的还是锁上的。当一个线程到来时,首先判断锁是否为开,如果是,则进入,并把锁锁上,其他线程就无法进来了。该线程执行完之后,离开,并把锁置为打开状态,以便其他线程进入。如果锁是锁上的,则进不去。


加锁后的Ticket函数为:

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


同步的前提

1.必须要有两个或两个以上的线程

2.必须是多个线程使用同一个锁

3.必须保证同步中只能有一个线程在运行

 

好处:解决了多线程的安全问题。

弊端:多线程需要判断锁,较为消耗资源。

 

0 0
原创粉丝点击