A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 周一川 中级黑马   /  2013-4-13 23:08  /  1387 人查看  /  8 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

线程安全问题表现?原因?解决思想?解决具体的体现?

8 个回复

倒序浏览
表现:当多线程在同时操作被共享的数据时,在循环自减后,可能会超出条件的范围。

        原因:1,多个线程在操作共享的数据。
              2,操作共享数据的线程代码有多条。
              当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。
       
        解决思想:就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程是不可以
                  参与运算的。必须要当前线程把这些代码都执行完毕了后,其他线程才可以参与运算。在java中,同步
                  代码块就可以解决这个问题。
       
        解决的具体体现:
        synchronized(对象)
        {
           需要被同步的代码;
        }

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
其实就一句话:只要是有多个线程访问并修改某个变量或是区域的话,一定要加上同步设置(比如同步控制语句,互斥锁等等)。
回复 使用道具 举报
线程安全问题表现,原因,解决思想,解决具体的体现如下:
线程安全表现主要是,线程的不同步问题,例如毕老师举得那个售票例子,由于线程不安全,而售出了负的票数,这就是线程安全问题的唯一表现。
原因,就是比如两个线程之间在运行时,互相的争夺CUP的执行权,当一个线程没有执行完,另一个线程就抢先进入,导致出现线程安全隐患。
解决思想是,java为我们提供了同步代码块synchronized,我们有了锁的机制,保证了线程的同步,即结果了线程安全问题,同步代码块,或者同步函数,保证了两个或者多个以上的线程在持有相同锁的情况下,实现了同步,解决了线程安全隐患。
具体体现给你举个简单的例子:
class Single{
private static Single s=null;
private Single(){}
public static Single getIncetance(){
if(s==null){
synchronized (Single.class) {//此处加了锁,保证了线程的唯一,提高了线程的安全性,
if(s==null)
s=new Single();
}
}
return s;
}
}

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
当多多线程操作共享数据时就会出现线程安全问题。
因为CPU在处理多线程时,是在线程间做高速的切换,此时如果几个线程在操作共享数据 比如在操作一下代码
num就是共享数据,如果某个线程执行到num++;后执行权被抢走了,而没有往下执行。当下个线程进来时就又执行了一次num++;打印的结果就是错了的。此线程就不安全。需要枷锁,让一个线程执行完在让另一个线程进来。
int num=0;
public void run()
{
     num++;如果程序执行到这里,CPU执行权被抢走了,
    System.out.println(num);
}

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
线程安全问题的表现:在视频中毕老师通过讲述售票的例子,来说明问题的,结果出现了售出负数和0的票;

出现安全问题的原因:在售票例子中多个售票窗口在销售同一批票。销售的过程中有一个没有完成,而下一个售票口就卖出,两个售票口抢夺资源造成了安全问题;

解决办法:对于多条操作共享数据的语句,只能通过让一个线程操作完,再执行其他的线程;

具体体现就用到了同步;synchronized(对象)
                      {

                                    }
回复 使用道具 举报
易杰 中级黑马 2013-4-14 12:28:40
7#
1.产生安全问题的原因
多个线程操作同一个数据时,一个线程对数据的操作还没完成,另一个线就程获取了资源来操作同一个数据。从而使数据发生错误。
2.解决方式
线程同步:一个线程对共享数据的操作还没完成,其他线程变无法操作共享数据。
线程同步实现方式:
第一种方式:

使用synchronized 语句块,如:
synchronized(Object obj){
                                       
  ....多个线程操作共享数据的代码...

}

  第二种方式:

使用synchronized修饰的函数,如:

public synchronized void  方法名(参数){

  ....多个线程操作共享数据的代码...

                                                                         }
示例代码:
//1.编写Runable接口实现类
class Demo implements Runnable{
//定义一个私有的成员变量
private int tick = 100;
//创建一个Object对象。
Object  obj = new Object();
//覆盖Runnable接口中的run()方法
public void run(){
//编写多线程的执行代码
while(true){
//tick是d所指对象的私有属性,输入共享数据。将操作tick的语句放入synchronized()方法体中。
synchronized(obj){
if(tick>0){
//Thread.currentThread().getName()——获得当前运行的线程对象的名字。
System.out.println(Thread.currentThread().getName()+"剩余票数"+tick--);
}
}
}
}
}
//编写测试类。
public class Test(){
public static void main (String[] args){
//2.创建实现类对象
Demo d= new Demo();
//3.调用Thread类的构造函数,创建Thread类的对象(即线程对象)。将实现类对象传递给不同线程对象。使不同线程共享同一个数据。
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
Thread t3 = new Thread(d);
//4.调用Thread类的对象t 的start()方法开启线程
t1.start();
t2.start();
t3.start();
}
}

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
针对线程的安全问题的表现:
举个例子,加入你是供货商。你往一个仓库里面存放货物,这时仓库里货物总数为 num 个。等你放进去后,货物总数变成 num+1 个。这时又一个销售商来取货物。他取走一个,这时仓库里应该还剩余 num 个。但是我们知道,你和销售商都对一个变量num进行操作。如果在你往仓库放货物的同时,销售商来取货,这就容易引起安全问题。假如你打开仓库门,查看了一下计数器,发现仓库里有num个货物。由于你是存货,所以,你先把货放进去了,这时你拿到num,想对num加 1 ,但是这时销售商来了,他也要对num操作。这时你还没有对num+1成功,供货商却取到了num。并进行了num-1操作。然后销售商走了,正常情况下,这时仓库里还剩num-1个货物,等你再把num+1后,仓库应该有num个货物。但是前面说了,你是取到num后准备执行加 1 操作时,动作被打断了,你手里拿到的计数器数值是num而不是实际货物个数(num-1)。所以当你继续执行加1操作后,num变成了num+1.而事实上计数器应为num。所以发生了安全问题。这个问题不难理解。生活中很多例子都是这样的。还例如银行存钱。买火车票等待。

第二,出现安全问题的原因:就是因为都对共享变量进行了操作。如果能保证一个线程在对共享变量进行操作的时候,另一个线程进不去。就可以避免这种安全问题。不过安全问题只是可能会发生,不是绝对的

第三,解决的思想,也就是上面说的,控制住共享变量就行了
第四,解决的具体体现,可以通过同步代码块或同步函数解决。

同步代码块:
synchronized(对象)
{
需要同步的代码
}
希望能帮助你!

评分

参与人数 1技术分 +1 收起 理由
黄玉昆 + 1

查看全部评分

回复 使用道具 举报
黄玉昆 黑马帝 2013-4-14 14:15:09
9#
如果问题未解决,请继续追问,如果没有问题了,请将帖子分类 改为“已解决”,谢谢
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马