黑马程序员技术交流社区
标题: 多线程 [打印本页]
作者: 周一川 时间: 2013-4-13 23:08
标题: 多线程
线程安全问题表现?原因?解决思想?解决具体的体现?
作者: 李易烜 时间: 2013-4-13 23:16
表现:当多线程在同时操作被共享的数据时,在循环自减后,可能会超出条件的范围。
原因:1,多个线程在操作共享的数据。
2,操作共享数据的线程代码有多条。
当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算,就会导致线程安全问题的产生。
解决思想:就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程是不可以
参与运算的。必须要当前线程把这些代码都执行完毕了后,其他线程才可以参与运算。在java中,同步
代码块就可以解决这个问题。
解决的具体体现:
synchronized(对象)
{
需要被同步的代码;
}
作者: 崔宝东 时间: 2013-4-13 23:22
其实就一句话:只要是有多个线程访问并修改某个变量或是区域的话,一定要加上同步设置(比如同步控制语句,互斥锁等等)。
作者: _王涛 时间: 2013-4-14 00:00
线程安全问题表现,原因,解决思想,解决具体的体现如下:
线程安全表现主要是,线程的不同步问题,例如毕老师举得那个售票例子,由于线程不安全,而售出了负的票数,这就是线程安全问题的唯一表现。
原因,就是比如两个线程之间在运行时,互相的争夺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;
}
}
作者: HM王琦 时间: 2013-4-14 01:10
当多多线程操作共享数据时就会出现线程安全问题。
因为CPU在处理多线程时,是在线程间做高速的切换,此时如果几个线程在操作共享数据 比如在操作一下代码
num就是共享数据,如果某个线程执行到num++;后执行权被抢走了,而没有往下执行。当下个线程进来时就又执行了一次num++;打印的结果就是错了的。此线程就不安全。需要枷锁,让一个线程执行完在让另一个线程进来。
int num=0;
public void run()
{
num++;如果程序执行到这里,CPU执行权被抢走了,
System.out.println(num);
}
作者: 庄生晓梦 时间: 2013-4-14 11:20
线程安全问题的表现:在视频中毕老师通过讲述售票的例子,来说明问题的,结果出现了售出负数和0的票;
出现安全问题的原因:在售票例子中多个售票窗口在销售同一批票。销售的过程中有一个没有完成,而下一个售票口就卖出,两个售票口抢夺资源造成了安全问题;
解决办法:对于多条操作共享数据的语句,只能通过让一个线程操作完,再执行其他的线程;
具体体现就用到了同步;synchronized(对象)
{
}
作者: 易杰 时间: 2013-4-14 12:28
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();
}
}
作者: gerenvip 时间: 2013-4-14 12:32
针对线程的安全问题的表现:
举个例子,加入你是供货商。你往一个仓库里面存放货物,这时仓库里货物总数为 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(对象)
{
需要同步的代码
}
希望能帮助你!
作者: 黄玉昆 时间: 2013-4-14 14:15
如果问题未解决,请继续追问,如果没有问题了,请将帖子分类 改为“已解决”,谢谢
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |