Java多线程同步问题求助

qq1212 2014-09-11 01:08:23
下面的代码执行后肯定是有问题的,我希望显示的结果是在赋值前value的值是1,2,3,4....10(顺序乱没关系,但不能重复和漏了),重新赋值后自然都是8888了。搞不定啊搞不定,高手求助

代码如下:

public class ThreadMain {
Map<String,A> m = new HashMap<String, A>();

void putA(A a){
m.put("k", a);
}

void main(A a) {
int i = 10;
while(i > 0) {
B b = new B();
b.setValue(i);
a.setB(b);

R r = new R(m);
Thread t = new Thread(r);
t.start();

i--;
}
}

public static void main(String[] args) {
ThreadMain d = new ThreadMain();
A a = new A();
d.putA(a);
d.main(a);
}
}

class R implements Runnable{
Map<String,A> m;

R(Map<String,A> m){
this.m = m;
}

public void run() {
A a = m.get("k");
System.out.println("before set A.b.value is:"+a.getB().getValue());

B b = new B();
b.setValue(8888);
a.setB(b);

System.out.println("after set A.b.value is:"+a.getB().getValue());
}
}

class A {
private B b;
public B getB() {
return b;
}

public void setB(B b) {
this.b = b;
}
}

class B{
private int value;

public int getValue() {
return value;
}

public void setValue(int value) {
this.value = value;
}
}
...全文
376 12 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
飞翔的卡其啦 2014-09-12
  • 打赏
  • 举报
回复
把同步块代码改成synchronized (this),是不能达到锁的 效果的。 因为this代表的是当前线程对象,所以是对当前的线程对象加锁。也就是说每个线程都只是各自拥有了一把锁,这样锁的意义就失效。 而synchronized(ThreadMain.class)是对全局加锁,所以能到到达互斥的效果!
lchq_johnny 2014-09-12
  • 打赏
  • 举报
回复
引用 3 楼 wangzhidavl 的回复:
楼上的方法是有点取巧了,把多线程变成单线程运行了。 楼主的类里主线程里对A的实例做了改变,而在子线程里也对A的实例做了改变,所里这里做不了同步,应该把对A的修改全放在子线程里,把修改的代码块加上同步锁即可。如下:

import java.util.HashMap;
import java.util.Map;



public class ThreadMain {
    Map<String,A> m = new HashMap<String, A>();
	
	void putA(A a){
		m.put("k", a);
	}
	
	void main(A a) {
		int i = 10;
		while(i > 0) {
//			B b = new B();
//			b.setValue(i);
//			a.setB(b);
			
			R r = new R(m,i);
			Thread t = new Thread(r);
			t.start();
			i--;

		}
	}
	
	public static void main(String[] args) {
		ThreadMain d = new ThreadMain();
		A a = new A();
		d.putA(a);
		d.main(a);
	}
}

class R implements Runnable{
	Map<String,A> m;
	int i;
	
	R(Map<String,A> m,int i){
		this.m = m;
		this.i = i;
	}

	public void run() {
		synchronized(ThreadMain.class){
			A a = m.get("k");
		    B b = new B();
		    b.setValue(i);
		    a.setB(b);
			System.out.println("before set A.b.value is:" + a.getB().getValue());

			b = new B();
			b.setValue(8888);
			a.setB(b);

			System.out.println("after set A.b.value is:" + a.getB().getValue());
		}
	}
}

class A {
	private B b;	
	public B getB() {
		return b;
	}

	public void setB(B b) {
		this.b = b;
	}
}

class B{
	private int value;

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}
}

请问为什么把46行换成如下: synchronized (this){ 输出的结果有可能就不对了,执行多次后,出现如下结果: before set A.b.value is:10 after set A.b.value is:8888 before set A.b.value is:8 after set A.b.value is:8888 before set A.b.value is:6 after set A.b.value is:8888 before set A.b.value is:9 after set A.b.value is:8888 before set A.b.value is:4 after set A.b.value is:8888 before set A.b.value is:2 after set A.b.value is:8888 before set A.b.value is:7 before set A.b.value is:8888 after set A.b.value is:8888 after set A.b.value is:8888before set A.b.value is:3 after set A.b.value is:8888 before set A.b.value is:1 after set A.b.value is:8888 观察红色部分,显然,synchronized块执行的过程中,被其他线程打断了,难道对R对象加锁之后,没有完全锁住吗?请大哥分析一下
qq1212 2014-09-12
  • 打赏
  • 举报
回复
3楼的大虾思路不错,我看看能不能改造下代码
qq1212 2014-09-12
  • 打赏
  • 举报
回复
引用 4 楼 wu244534279 的回复:
实际上我不知道楼主这个代码是想干什么的,一个对象传来传去,对象之间的关系乱七八糟的,新手就不要写这么复杂嘛,先学学消费者-生产者模式吧
大大说的是,这么写代码是因为生产代码就是这样的,我还没到重构的水平。 原代码这么写是为了方便Map作为全局缓存对里面的对象根据不同的条件赋值再在其他类里面使用,我觉得也有点别扭,而且现在在多线程的情况下又出现了好麻烦的bug
lchq_johnny 2014-09-12
  • 打赏
  • 举报
回复
引用 11 楼 lchq_johnny 的回复:
[quote=引用 8 楼 lyy5682077 的回复:] 把同步块代码改成synchronized (this),是不能达到锁的 效果的。 因为this代表的是当前线程对象,所以是对当前的线程对象加锁。也就是说每个线程都只是各自拥有了一把锁,这样锁的意义就失效。 而synchronized(ThreadMain.class)是对全局加锁,所以能到到达互斥的效果!
懂了,分析的非常透彻,多谢![/quote] 补充一点,this代表的是R对象,因为每次循环都是new R(), 所以synchronized(this)是分别对每个R对象加锁,这些锁之间互不干扰,所以每个线程都能拿到自己的R对象锁然后执行synchronized块里的代码,这样就是锁不住的原因;如果R对象是单例的,每次循环拿到的都是同一个R对象,那么synchronized(this)就是对单例的那个R对象加锁,自始至终只有这一个锁,这样的话每个线程要想执行synchronized块里的代码,必须得拿到那个唯一的R对象锁,这样就起到锁的作用了。 以上是我个人的理解,有不对的地方请指出,谢谢!
lchq_johnny 2014-09-12
  • 打赏
  • 举报
回复
引用 8 楼 lyy5682077 的回复:
把同步块代码改成synchronized (this),是不能达到锁的 效果的。 因为this代表的是当前线程对象,所以是对当前的线程对象加锁。也就是说每个线程都只是各自拥有了一把锁,这样锁的意义就失效。 而synchronized(ThreadMain.class)是对全局加锁,所以能到到达互斥的效果!
懂了,分析的非常透彻,多谢!
ydarin 2014-09-12
  • 打赏
  • 举报
回复
程序略作修改。ThreadMain 给R传m后,不要直接用this.m=m;因为是引用类型,两个m指向的是同一个实例,每个线程操作的都是你ThreadMain的m。R中m重新new一个,下面的a,b都要new,只复制个value。 import java.util.Map; import java.util.HashMap; public class ThreadMain { Map<String,A> m = new HashMap<String, A>(); void putA(A a){ m.put("k", a); } void main(A a) { int i = 10; while(i > 0) { B b = new B(); b.setValue(i); a.setB(b); R r = new R(m); Thread t = new Thread(r); t.start(); i--; } } public static void main(String[] args) { ThreadMain d = new ThreadMain(); A a=new A(); d.putA(a); d.main(a); } } class R implements Runnable{ Map<String,A> m; R(Map<String,A> m){ A a=m.get("k"); B b=a.getB(); int v=b.getValue(); B b1=new B(); b1.setValue(v); A a1=new A(); a1.setB(b1); this.m = new HashMap<String, A>(); this.m.put("k", a1); } public void run() { A a = m.get("k"); System.out.println("before set A.b.value is:"+a.getB().getValue()); B b = new B(); b.setValue(8888); a.setB(b); System.out.println("after set A.b.value is:"+a.getB().getValue()); } } class A { private B b; public B getB() { return b; } public void setB(B b) { this.b = b; } } class B{ private int value; public int getValue() { return value; } public void setValue(int value) { this.value = value; } }
ydarin 2014-09-12
  • 打赏
  • 举报
回复
楼主的程序中的M实例自始至终只有一个,所有的操作都是对M的一个实例的操作,当所有的线程开始时,m.a.b.value都已经从10,9,变到1。要想能输出123...... .必须每个循环创造一个实例。要真想只用一个实例,就不要用线程了,循环一个一个操作。
wu244534279 2014-09-11
  • 打赏
  • 举报
回复
看20~24行。
wu244534279 2014-09-11
  • 打赏
  • 举报
回复
public class ThreadMain {
	Map<String,A> m = new HashMap<String, A>();
	
	void putA(A a){
		m.put("k", a);
	}
	
	void main(A a) {
		int i = 10;
		while(i > 0) {
			B b = new B();
			b.setValue(i);
			a.setB(b);
			
			R r = new R(m);
			Thread t = new Thread(r);
			t.start();
			i--;
			
			try {
				t.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
		}
	}
	
	public static void main(String[] args) {
		ThreadMain d = new ThreadMain();
		A a = new A();
		d.putA(a);
		d.main(a);
	}
}

class R implements Runnable{
	Map<String,A> m;
	
	R(Map<String,A> m){
		this.m = m;
	}

	public void run() {
		A a = m.get("k");
		System.out.println("before set A.b.value is:"+a.getB().getValue());
		
		B b = new B();
		b.setValue(8888);
		a.setB(b);
		
		System.out.println("after set A.b.value is:"+a.getB().getValue());
	}
}

class A {
	private B b;	
	public B getB() {
		return b;
	}

	public void setB(B b) {
		this.b = b;
	}
}

class B{
	private int value;

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}
}
wu244534279 2014-09-11
  • 打赏
  • 举报
回复
实际上我不知道楼主这个代码是想干什么的,一个对象传来传去,对象之间的关系乱七八糟的,新手就不要写这么复杂嘛,先学学消费者-生产者模式吧
wangzhidavl 2014-09-11
  • 打赏
  • 举报
回复
楼上的方法是有点取巧了,把多线程变成单线程运行了。 楼主的类里主线程里对A的实例做了改变,而在子线程里也对A的实例做了改变,所里这里做不了同步,应该把对A的修改全放在子线程里,把修改的代码块加上同步锁即可。如下:

import java.util.HashMap;
import java.util.Map;



public class ThreadMain {
    Map<String,A> m = new HashMap<String, A>();
	
	void putA(A a){
		m.put("k", a);
	}
	
	void main(A a) {
		int i = 10;
		while(i > 0) {
//			B b = new B();
//			b.setValue(i);
//			a.setB(b);
			
			R r = new R(m,i);
			Thread t = new Thread(r);
			t.start();
			i--;

		}
	}
	
	public static void main(String[] args) {
		ThreadMain d = new ThreadMain();
		A a = new A();
		d.putA(a);
		d.main(a);
	}
}

class R implements Runnable{
	Map<String,A> m;
	int i;
	
	R(Map<String,A> m,int i){
		this.m = m;
		this.i = i;
	}

	public void run() {
		synchronized(ThreadMain.class){
			A a = m.get("k");
		    B b = new B();
		    b.setValue(i);
		    a.setB(b);
			System.out.println("before set A.b.value is:" + a.getB().getValue());

			b = new B();
			b.setValue(8888);
			a.setB(b);

			System.out.println("after set A.b.value is:" + a.getB().getValue());
		}
	}
}

class A {
	private B b;	
	public B getB() {
		return b;
	}

	public void setB(B b) {
		this.b = b;
	}
}

class B{
	private int value;

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}
}

62,635

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧