多线程并发问题

magicblue 2011-07-18 11:39:57
class A
{
int i = 0;
List<Integer> a = new ArrayList<Integer>();

int f1(int j) {
return a.get(j);
}
int f2(int j) {
return j + a.get(j);
}
List<Integer> f3() {
return a;
}
List<Integer> f4() {
List<Integer> b = new ArrayList<Integer>();
b.addAll(a);
return b;
}
}

同一个A对象被多线程并发,f1,f2,f3,f4哪个需要加锁?
...全文
544 点赞 收藏 33
写回复
33 条回复
xiaokangbuben 2011年08月04日
刚学到线程 ,还不是很懂
回复 点赞
BadPattern 2011年08月04日
不需要,23楼说的很清楚啦。只有结构修改才需要同步
回复 点赞
daijope 2011年08月01日
都是读方法,不用加锁的,你可以把成员变量申明为final,没有set方法,就不用加锁了。
回复 点赞
JavaMan_KA 2011年08月01日
不应该加锁吧,加了反而画蛇添足。
回复 点赞
chenchengamao 2011年08月01日
如果get方法的返回值的状态不仅仅是靠传入的参数决定的,那么 f1和f2 都要用synchronized,其它都不用。
回复 点赞
Mybeautiful 2011年07月26日
[Quote=引用 25 楼 leisore 的回复:]

LZ当前的写法在没有对调用者作出约束前没有办法保证线程安全
只分析与f1~f4有关的成员变量a
A声明是package可见的,同包下的类可以访问,并且可以直接访问A.a
假设类B和A在同一个包下,B在多线程环境下使用A的实例
而A.a本身不是线程安全的,所以无论怎么对f1~f4加锁,都没有办法
保证B通过A.a的方式拿到a的引用从而修改a的内容,导致A中所有加锁的地方都是徒劳
因为A……
[/Quote]
有道理,不能瞎暴露,太暴露不安全。
回复 点赞
walkerdead 2011年07月22日
无需加锁
回复 点赞
liuzhengkang 2011年07月22日
不需要,因为这里list a没有做修改。
引api的一段话:
“如果多个线程同时访问一个 ArrayList 实例,而其中至少一个线程从结构上修改了列表,那么它必须 保持外部同步。(结构上的修改是指任何添加或删除一个或多个元素的操作,或者显式调整底层数组的大小;仅仅设置元素的值不是结构上的修改。)这一般通过对自然封装该列表的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedList 方法将该列表“包装”起来。这最好在创建时完成,以防止意外对列表进行不同步的访问:

List list = Collections.synchronizedList(new ArrayList(...)); ”
回复 点赞
tu1129287460 2011年07月22日
都不需要加吧,个人认为的。。。。。
回复 点赞
abcsucker 2011年07月22日
这么专业,根本不懂。
回复 点赞
leisore 2011年07月22日
LZ当前的写法在没有对调用者作出约束前没有办法保证线程安全
只分析与f1~f4有关的成员变量a
A声明是package可见的,同包下的类可以访问,并且可以直接访问A.a
假设类B和A在同一个包下,B在多线程环境下使用A的实例
而A.a本身不是线程安全的,所以无论怎么对f1~f4加锁,都没有办法
保证B通过A.a的方式拿到a的引用从而修改a的内容,导致A中所有加锁的地方都是徒劳
因为A中加锁,无非针对A或A.a,但是都没有办法阻止B的A.a操作
回复 点赞
商科程序员 2011年07月18日
[Quote=引用 9 楼 chouy 的回复:]
加不加锁是业务决定的,不是技术决定的.
[/Quote]也就是说,技术上你可以选择加,这样肯定不会出错.但业务上你要通过业务流程分析,得出哪个需要加,那个不需要加的结论.不需要加的你加了,顶多是影响性能.应该也不会对系统有影响.

如果是我,我会在f1,f2,f4上加,f3不加.
回复 点赞
magicblue 2011年07月18日
难道我贴的伪代码太差了?我觉得很容易看懂啊
什么加锁由业务决定都来了。。。你们好好看伪代码了吗
回复 点赞
商科程序员 2011年07月18日
加不加锁是业务决定的,不是技术决定的.
回复 点赞
AslenG 2011年07月18日
[Quote=引用 6 楼 wula0010 的回复:]

楼主举的例子不好,例子里面a永远都是空的,这样b永远也是空的,所以加锁不加锁都没问题。线程中,如果存在修改可能导致读取到不同的数据,就需要加锁。比如下面的类,如果在不同的线程中分别调用f1和f2,就需要加锁。
Java code

class A
{
int a

int f1() {
return a;
}

int f2(int j) {
a=a+j;
r……
[/Quote]
LZ那是伪代码额……
回复 点赞
贪睡的兔子 2011年07月18日
arrayList是线程不安全的,都要
回复 点赞
wula0010 2011年07月18日
楼主举的例子不好,例子里面a永远都是空的,这样b永远也是空的,所以加锁不加锁都没问题。线程中,如果存在修改可能导致读取到不同的数据,就需要加锁。比如下面的类,如果在不同的线程中分别调用f1和f2,就需要加锁。

class A
{
int a

int f1() {
return a;
}

int f2(int j) {
a=a+j;
return a;
}
}


回复 点赞
magicblue 2011年07月18日
例子只是个示意,能够说明意思就可以了。
f1,f2,f3应该是不用的,因为每个线程有自己的thread stack。f4需要
但我不是很确定。因为java的线程机制,网上说的很清楚的不多。
回复 点赞
Mybeautiful 2011年07月18日
楼主的 a这个list根本一直是空的,除非有调用f3修改。

是否需要加锁是跟具体业务寻求,运行场景有关;估计 你的例子中,f1--f4,全部要加锁。形如:


int synchronized f1(int j) {
return a.get(j);
}
回复 点赞
AlexLee8810 2011年07月18日
路过,就为下点东西,容易吗?
回复 点赞
发动态
发帖子
Java SE
创建于2007-09-28

3.4w+

社区成员

30.7w+

社区内容

Java 2 Standard Edition
社区公告
暂无公告