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哪个需要加锁?
{
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哪个需要加锁?
int index=0;
String[] str={"you","are","me","me","are","you"};
public void run() {
while (true) {
System.out.println(str[index++%6]);
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new Case().start();
}
}
你可以在f1中 写while (true) Thread.sleep(1000)等待一下
int synchronized f1(int j) {
return a.get(j);
}
f1,f2,f3应该是不用的,因为每个线程有自己的thread stack。f4需要
但我不是很确定。因为java的线程机制,网上说的很清楚的不多。
{
int a
int f1() {
return a;
} int f2(int j) {
a=a+j;
return a;
}
}
至于f4,其实也是可以被并发的。关键看对b的操作有没有用到共享数据。如果没有,就无需加锁
如果有个线程在动态修改list里的值,只需要在修改这个list时,对这个list加个锁就行了,防止只修改了一半,未修改完的情况下,其它线程读取到脏数据.
{
int i = 0;
List<Integer> a = new ArrayList<Integer>();
void f0(int i){
a.add(i);
}
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;
}
}加上一个添加方法后就都需要加锁了, 都是为了防止脏读 ,其实这样可以联想到读写锁 , 你应该学过操作系统吧 就累死于读者写着问题。读写加互斥锁,读锁只要有一个在读那所有读锁都可以加入。
jvm 是这样管理内存的 ,创建的对象都是保存在 堆中的,java栈是线程独享的,每个java栈由栈帧组成,存储线程中java方法的调用状态,包括局部变量,被调用时传进来的参数,返回值,以及运算的中间结果。堆中的对象是被共享的在JVM中每个对象都有一个对象锁,具体的锁操作看书本吧。 ArrayList 是线程不安全的容器,所以在list上执行的操作都需要加锁。 CopyOnWriteArrayList 实现了无锁容器~~ 你可以看一下。
引api的一段话:
“如果多个线程同时访问一个 ArrayList 实例,而其中至少一个线程从结构上修改了列表,那么它必须 保持外部同步。(结构上的修改是指任何添加或删除一个或多个元素的操作,或者显式调整底层数组的大小;仅仅设置元素的值不是结构上的修改。)这一般通过对自然封装该列表的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedList 方法将该列表“包装”起来。这最好在创建时完成,以防止意外对列表进行不同步的访问: List list = Collections.synchronizedList(new ArrayList(...)); ”
只分析与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操作