论坛首页 综合技术论坛

多线程开发,表示很凌乱

浏览 12473 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-04-19  
zfc827 写道
junlas 写道

嗯,非常感谢回复这么多,还是可以理解的。我把我的一个疑惑描述一下,可能有点2。有一种这样的情况,唯一的一个共享数据对象O,内部有方法A,方法B,起了5个线程去执行方法A,起了另外3个线程执行方法B,好的,请教,在方法A、B中:

1.访问对象O中的普通类变量需要synchronized,如果不是普通类变量,是java.util.concurrent包下的类型变量,就不用synchronized了,这点没错吧,如果没错,我理解的应该就没错。正如你上面所说。

2.方法A、B中的参数、临时变量,是否也需要synchronized?这是比较疑惑的了,我发帖的主要原因。我的理解是:线程1可能正执行到方法A、B的一半时,被切到线程2来执行这个方法,因为参数和临时变量没synchronized,这个值就变了??

 

我觉得是我肯定理解错了?求指点,如何理解呢

有几天没来看这个帖子了,可能我没说明白,楼主要明确,只有类变量有线程安全的问题!!!,方法中定义的临时变量,以及方法中传入的任何参数,都不存在线程安全问题!!!

线程执行1个方法时创建的所有临时变量都由线程自己维护,比如:2个线程执行同1个方法,那么创建的临时变量是2份,他们之间没有任何关系!!!

上面说法可能理解会有错误,楼主如果站在一个对象的内部来考虑线程安全,那么上面说法是正确的,但如果从类的外部来考虑,比如:如果一个方法的参数是一个对象,而多个线程调用该方法时传入的参数是同一个对象,那么这个对象确实不是线程安全的。这是由于参数的引用传递导致。我对线程的理解并没有深入到JVM实现中去,但是希望给楼主提供一个简单的思路去考虑线程安全。

下面举个例子:

public void run() {
     Model object = new Model();
     object.changeMap1();
     object.changeMap2();
}


public class Model{
     private static Map map1 = new HashMap();

     private Map map2 = new HashMap();

     public void changeMap1() {
        //.....change map1
     }

     public void changeMap2() {
        //.....change map2
     }
}

 run方法中,他创建了一个Model对象。Model类中,定义有2个map和2个操作对应map的方法,其中map1是static的。楼主现在能判断这2个changeMap方法是不是线程安全的吗?

如果不能,以下是思路:

1、首先明确,类变量才有线程安全问题,在Model类内部,咋看之下这2个方法都不是线程安全的,因为他们都改变了类变量map的值。

2、但是跳出Model类,在run方法中,Model的实例object是run方法的一个临时变量,那么就发生了变化,多个线程执行run方法时,会创建多个Model对象,Model对象中的map2也会有多个且之间没有任何关系,所以changeMap2方法是线程安全的,因为他们根本不是访问的同一个map。

3、同理,虽然多线程也创建了多个Model对象,但是对map1而言,因为他是static的,map1只会创建一次!是单例的!,所有线程在调用changeMap1方法时都是访问同一个map,所以changeMap1不是线程安全的方法,需要加上synchronized关键字标识。

0 请登录后投票
   发表时间:2012-04-20  
成员变量会有线程并发问题,局部变量和方法的参数是没有并发问题的。
0 请登录后投票
   发表时间:2012-04-20  
关键是线程,线程的中断,以及涉及到线程与主线程之间的通信,比较麻烦,以及难以控制,多线程是梦靥
0 请登录后投票
   发表时间:2012-04-20  
zfc827 写道

有几天没来看这个帖子了,可能我没说明白,楼主要明确,只有类变量有线程安全的问题!!!,方法中定义的临时变量,以及方法中传入的任何参数,都不存在线程安全问题!!!

线程执行1个方法时创建的所有临时变量都由线程自己维护,比如:2个线程执行同1个方法,那么创建的临时变量是2份,他们之间没有任何关系!!!

/**
	 * 还是要看目标对象被并发使用的上下文有几个,跟是不是方法的local变量没关系吧
	 */
	private void dummy() {
		//这是个方法内的本地变量吧?
		final AtomicInteger ai = new AtomicInteger(0);
		for (int i=0; i<10; i++) {
			ai.incrementAndGet();
			new Thread() {
				public void run() {
					ai.decrementAndGet();
				}
			}.start();
		}
		System.out.println(ai);//等于几?
	}
 
0 请登录后投票
   发表时间:2012-04-20  
你这情况应该看NIO了吧。
0 请登录后投票
   发表时间:2012-04-20  
atomduan 写道
zfc827 写道

有几天没来看这个帖子了,可能我没说明白,楼主要明确,只有类变量有线程安全的问题!!!,方法中定义的临时变量,以及方法中传入的任何参数,都不存在线程安全问题!!!

线程执行1个方法时创建的所有临时变量都由线程自己维护,比如:2个线程执行同1个方法,那么创建的临时变量是2份,他们之间没有任何关系!!!

 

/**
	 * 还是要看目标对象被并发使用的上下文有几个,跟是不是方法的local变量没关系吧
	 */
	private void dummy() {
		//这是个方法内的本地变量吧?
		final AtomicInteger ai = new AtomicInteger(0);
		for (int i=0; i<10; i++) {
			ai.incrementAndGet();
			new Thread() {
				public void run() {
					ai.decrementAndGet();
				}
			}.start();
		}
		System.out.println(ai);//等于几?
	}
说的没错,但是也只有这样类似闭包的写法才有问题,对于初学者而言,这种情况大多数都不作考虑。实际上对于run方法而言,ai就是一个单例对象。

 

0 请登录后投票
   发表时间:2012-04-23   最后修改:2012-04-23
zfc827 写道
atomduan 写道
zfc827 写道

有几天没来看这个帖子了,可能我没说明白,楼主要明确,只有类变量有线程安全的问题!!!,方法中定义的临时变量,以及方法中传入的任何参数,都不存在线程安全问题!!!

线程执行1个方法时创建的所有临时变量都由线程自己维护,比如:2个线程执行同1个方法,那么创建的临时变量是2份,他们之间没有任何关系!!!

 

/**
	 * 还是要看目标对象被并发使用的上下文有几个,跟是不是方法的local变量没关系吧
	 */
	private void dummy() {
		//这是个方法内的本地变量吧?
		final AtomicInteger ai = new AtomicInteger(0);
		for (int i=0; i<10; i++) {
			ai.incrementAndGet();
			new Thread() {
				public void run() {
					ai.decrementAndGet();
				}
			}.start();
		}
		System.out.println(ai);//等于几?
	}
说的没错,但是也只有这样类似闭包的写法才有问题,对于初学者而言,这种情况大多数都不作考虑。实际上对于run方法而言,ai就是一个单例对象。

 

 

 

嗯。。。

0 请登录后投票
   发表时间:2012-04-23  
leu 写道
zfc827 写道
atomduan 写道
zfc827 写道

有几天没来看这个帖子了,可能我没说明白,楼主要明确,只有类变量有线程安全的问题!!!,方法中定义的临时变量,以及方法中传入的任何参数,都不存在线程安全问题!!!

线程执行1个方法时创建的所有临时变量都由线程自己维护,比如:2个线程执行同1个方法,那么创建的临时变量是2份,他们之间没有任何关系!!!

 

/**
	 * 还是要看目标对象被并发使用的上下文有几个,跟是不是方法的local变量没关系吧
	 */
	private void dummy() {
		//这是个方法内的本地变量吧?
		final AtomicInteger ai = new AtomicInteger(0);
		for (int i=0; i<10; i++) {
			ai.incrementAndGet();
			new Thread() {
				public void run() {
					ai.decrementAndGet();
				}
			}.start();
		}
		System.out.println(ai);//等于几?
	}
说的没错,但是也只有这样类似闭包的写法才有问题,对于初学者而言,这种情况大多数都不作考虑。实际上对于run方法而言,ai就是一个单例对象。

 

受教了,对于我而言,我还是会尽量避免这种写法。。

0 请登录后投票
   发表时间:2012-05-17  
我的理解是,当两个以上线程共享并操作同一个变量时, 很容易发生原子性和一致性的问题,被共享的变量操作就需要进行同步,比如线程1进行i++同步时,线程2取得i就会等待,线程1操作结束线程2才开始操作i
0 请登录后投票
   发表时间:2012-05-18  
aa87963014 写道
junlas 写道
aa87963014 写道
有2个方法操纵一个map对象,怎么实现线程安全?
2个方法都加上锁?



一般我都是用ConcurentHashMap这个对象


不是这个意思


多线程访问的时候,只需要对 共享的对象加锁。 操作共享对象的方法是不需要加锁的

还有一点就是:如果某个方法里面有多个共享对象,在方法加锁,是为了保证这个方法操作的原子性。
0 请登录后投票
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics