多线程安全问题
来源:互联网 发布:山东直销软件开发 编辑:程序博客网 时间:2024/05/18 20:49
对于一个多线程的程序,在其并发的执行过程中可能会因为资源的竞争而出现安全问题,比如对于一个售票系统,当几个窗口并发的去运行时可能会出现与实际不符合的现象,如下面的卖票程序:
class Ticket implements Runnable
{
private int tick = 100;
public void run()
{
while (true)
{
if (tick>0)
{ System.out.println(currentThread().getName()+"sale:"+tick--);
}
}
}
}
class ThreadDemo
{
public static void main(String[] args)
{
Ticket t = new Ticket();
Thread t1 = new Thread (t);//创建一个线程,并将ticket对象传递给thread的构造函数
Thread t2 = new Thread (t);
Thread t3 = new Thread (t);
Thread t4 = new Thread (t);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
在上面的程序执行中,可能会出现这样的情况:当tick = 1时,四个线程就有可能出现下面的情况:
0号线程判断后,进入循环内部后阻塞,cpu切换到其他程序,此时tick=1;
1号线程判断后,进入循环内部后阻塞,cpu切换到其他程序,此时tick仍然等于1;
2号线程判断后,进入循环内部后阻塞,cpu切换到其他程序,此时tick还是等于1;
3号线程判断后,进入循环内部后阻塞,cpu切换到其他程序,此时tick继续保持为1的状态。
当4个线程都被阻塞后,cpu可能会切换至0号线程(因为cpu总是会切换至线程池前面的等待线程),运行后自然打印出1号票并将tick置为0,而后续的等待线程依次被唤醒,执行后就会打印出-1号-2号-3号票,这显然是与现实生活中的实际情况是不相符的。
问题原因:
为什么会出现这样的问题呢?分析代码后很容易就找出了原因所在,当每个线程在对某一共享数据操作时用到了多条语句时,就会出现只执行了多条语句的部分语句后就被阻塞的情况,而就在这时其他线程又参与进来执行,从而导致了共享数据的错误,发生了与现实不符合的情况。
解决的方法:
如果我们让有多条语句的线程在执行时不被其他线程“所打扰”,就能实现某一线程对共享数据的单独操作,待其操作完成后,再让其他线程进入并执行就不会出现上述的情况了,那么我们如何用代码实现这一思想呢?对此,java提供了专业的解决办法,这就是同步代码块。其格式为:
Synchronized(对象)
{
//需要执行的代码(运行时共享的代码)
}
上面的卖票程序操作共享数据的代码部分可以做如下的修改:
public void run()
{
While(true)
{
Object obj = new Object();//
Synchronized(obj)
{
if (tick>0)
System.out.println(currentThread().getName()+"sale:"+tick--);
}
}
}
同步代码块的对象就如同锁,持有锁的线程可以在同步代码块中执行,没有持有锁的线程即便是获得了cpu的执行权,也执行不下去,因为他并没有锁。在使用同步代码块时,必须要有两个或两个以上的线程,必须是多个线程使用同一个锁。
通过同步代码块的加入就能解决安全问题,但同时也有了一个弊端,那就是多个线程需要判断锁,较为消耗资源。
如何在一个多线程的代码中来找可能出现问题的代码呢?基于此,我们应按以下三步来做:
1, 明确哪些代码是多线程运行的代码。
2, 明确哪些是共享数据
3, 明确多线程运行代码中哪些语句是操作共享数据的。
明确了上面的3个问题,就知道哪些代码应置于同步代码块中,也即是用同步代码块来封装共享数据的代码,这样就能解决多线程的安全问题。同样,函数也是封装代码的,如果我们使某一函数具有同步性,那也可以解决安全问题,如上面的问题用同步函数来解决的简化代码如下:
public Synchronized void run()
{
if (tick>0) System.out.println(currentThread().getName()+"sale:"+tick--);
}
不同与同步代码块,同步函数使用时是不需要对象的,它所使用的锁是this,也即当某一线程进入时就会拿到本线程对应的锁。---------------------- android培训、java培训、期待与您交流! ----------------------
- 多线程安全问题
- 多线程安全问题
- 多线程安全问题
- 多线程安全问题
- 多线程安全问题。
- 多线程安全问题
- 多线程(多线程的安全问题)
- 多线程02--多线程安全问题
- Servlet多线程安全问题
- servlet多线程安全问题
- Servlet多线程安全问题
- Servlet多线程安全问题
- Servlet多线程安全问题
- Servlet多线程安全问题
- 多线程的安全问题
- Servlet多线程安全问题
- STL的多线程安全问题
- STL的多线程安全问题
- 给按钮、静态文本 CListCtrl等添加功能提示(tollTip)功能
- 保持service一直在后台运行
- 程序员应该用程序来思维,有空来研究一下狼 羊 草和农夫过河,将算法转换为代码《转》
- Struts2源码浅析-Container
- 成为一名优秀程序员所需要知道的那些事
- 多线程安全问题
- linux 修改系统时间命令
- PHP Socket 编程
- 初学Java,IO之推回输入流(四十四)
- 千万级别mysql合并表快速去重
- 苹果电脑数据备份和数据恢复方法+时间机器
- 关于读C++语言的设计和演化
- Javascript + Asp.net 让图片自动成比例缩放
- nachos 扩展文件长度