论坛首页 入门讨论版

请教一个基本问题

浏览 2038 次
该帖已经被评为新手帖
作者 正文
时间:2006-12-14
小弟这厢有礼了,对java学的不好,大侠们别见笑,请教一个基本问题,关于线程同步的:
class A{
private static final A instance = new A();
private String s;

private A(){}

public static A getInstance(){return instance;}

public void setS(String s){this.s = s;}

public String getS(){return this.s;}
}
这是一个简单的单例,如果有两个线程L1和L2同时调用A.getInstance().setA或者A.getInstance().getA,不知道是不是存在线程同步问题?谢谢
   
时间:2006-12-14
我认为需要线程同步
   
0 请登录后投票
时间:2006-12-14
唉,没人帮忙我就说说自己的理解吧,各位指正,常年在javaeye只看贴,深知eye的高人多,砖更多:)
我认为getS没用线程安全问题,主要是setS,因为改写了共享资源 s,所以修改setS为
public synchronized void setS(String s){this.s = s;}
不知道这么说对不对
   
0 请登录后投票
时间:2006-12-14
嘿嘿,没想到跟楼上的兄弟同时发
提出这个问题是因为这两天初学spring,对于spring的默认单例很困惑:
class Service(){
Dao dao;
public void setDao(Dao dao){this.dao = dao;}

public void Test(){dao.***();}
}
用BeanFactory创建的Service是单例的,而这个私有属性dao为什么没用线程安全问题呢?这个地方我有些想不明白,希望有人点拨点拨,先谢了
   
0 请登录后投票
时间:2006-12-14
这个service是由容器创建的,容器只会初始化一次,所以dao没有写冲突,这样不加锁也可以
   
0 请登录后投票
时间:2006-12-14
线程同步只需要在“共享修改”时才需要。比如:
class A{
  private ArrayList<Integer> arr;
  public void insert(int idx, int value){
    // ...
  }
  public void remove(int idx){
    // ...
  }
}

这2个方法操作同一个对象,是要同步的,因为每个操作都可能改变对象内部状态,导致另一个操作非法访问。

而你这里只是赋值,这个部分由JVM保证它是原子的,对象内部状态不改变,所以不需要同步。

public class Foo {
	private String foo = "abc";
	
	class TestThread extends Thread{
		public void run(){
			System.out.println("Thread Start");
			for (int i=0; i<10000000; ++i){
				foo = foo.substring(1) + "a";
				foo = new String("def");
			}
			System.out.println("Thread End");
		}
	}
	
	public void test() throws InterruptedException{
		Thread[] threads = new TestThread[10];
		
		for (int i=0; i<threads.length; ++i){
			threads[i] = new TestThread();
			threads[i].start();
		}
		
		for (int i=0; i<threads.length; ++i){
			threads[i].join();
		}
	}

	public static void main(String[] args) throws InterruptedException {
		System.out.println("Start");
		Foo foo = new Foo();
		foo.test();
		System.out.println("End");
	}
}


测试N多次没有问题。。

实际上决定因素不是“对象内部状态改变与否”,而不这些状态改变会不会让其它的共享访问/修改非法。
   
0 请登录后投票
时间:2006-12-14
感谢楼上的兄弟们,测试了一下,果然如deafwolf所说,service和dao都是单例,也就是说setDao只执行一次,不存在同步问题。
   
0 请登录后投票
时间:2006-12-14
qiezi老兄说的这个我就不明白了,好像跟网上看到的单例同步问题冲突了:
class A{
private static final A instance = null;
private String s;

private A(){}

public static A getInstance(){
if(instance==null)instance=new A();
return instance;
}
按网上的说法,这种单例模式是有同步问题的;看似qiezi的说法跟这个有点冲突
   
0 请登录后投票
时间:2006-12-14
wtusmchen 写道
qiezi老兄说的这个我就不明白了,好像跟网上看到的单例同步问题冲突了:
class A{
private static final A instance = null;
private String s;

private A(){}

public static A getInstance(){
if(instance==null)instance=new A();
return instance;
}
按网上的说法,这种单例模式是有同步问题的;看似qiezi的说法跟这个有点冲突

我没有演示单例,我说明的是多个线程多次set/get没有同步问题,也就是你说的getA和setA的同步问题,这实际上和单例没什么关系了。

你上面这个单例模式所说的同步问题其实也不是很严重,顶多后果可能是生成了多个实例,如果是针对单例来说,不想生成多个实例。你楼顶的帖子里的例子和上面这个不一样,不存在线程同步问题,因为已经初始化好了。
   
0 请登录后投票
时间:2006-12-14
说点个人看法
我没看明白qieziGG的那个Foo哪里有冲突了 那个确实是不会出问题的 因为每个线程设置给那个String的都是同一个值 就算是冲突也不可能看得出来

另外LZ对set方法同步是不对的 set不会有问题 有问题的 set+get
也就是我set了 我get 如果我set 你set 我get 得到你set的 那就是同步有问题的
对单一的set方法是没有必要同步的 应该是在外面 调用这个set这里 根据业务来决定是否要同步

LSS这个 确实是有可能有问题 因为get里面进行了new A() 也就是set 如果两个人同时运行这个 那么第1个就有可能拿到第2个人的 因为这个instance是static的 如果不是的话 就没有问题了 因为是两个Class


个人总结 同步要看get的那句 看你get得到的数据是否是你set进去的那个 如果不是 就需要
   
0 请登录后投票
论坛首页 入门讨论版

跳转论坛: