2013-11-25 68 views
1

嘿,我试图把线程作为一个概念。 让我画你一个场景线程何时共享对象? - Java

class A { 
    private int counter = 0; 

    public void add() { 
     counter++; 
    } 

    public int getCounter() { 
     return counter; 
    } 
} 

class B implements Runnable { 
    public void run() { 
     A a = new A(); 
     a.add(); 
     a.add(); 
    } 
} 

class C implements Runnable { 
    public void run() { 
     A a = new A(); 
     System.out.println(a.getCounter()); 
    } 
} 

什么是System.out.println给我,当我运行C? 我猜它给了我0,因为他们每个都创建了一个A的实例。

如果这是真的,你将如何分享线程之间的对象?

+2

请您正确格式化您的示例!它甚至没有编译。 – isnot2bad

回答

2

你不会在System.out上看到任何东西,因为你没有一个完整的程序。但是,假设你创建了两个线程,并且运行了B,然后运行C与另一个,是的,0会被打印出来,因为在你猜测的时候,每个线程都使用一个单独的A实例。这很好,因为A不会,没有任何内存障碍可以让它被多线程安全地访问。

要共享数据,您需要将一个对象传递给两个线程。例如:

final class Test { 

    public static void main(String[] argv) throws InterruptedException { 
    AtomicInteger shared = new AtomicInteger(); 
    Thread a = new B(shared).start(); 
    a.join(); 
    Thread b = new C(shared).start(); 
    b.join(); 
    } 

} 

final class B extends Thread { 

    private final AtomicInteger shared; 

    B(AtomicInteger shared) { this.shared = shared; } 

    @Override() 
    public void run() { 
    shared.getAndIncrement(); 
    shared.getAndIncrement(); 
    } 

} 

final class C extends Thread { 

    private final AtomicInteger shared; 

    C(AtomicInteger shared) { this.shared = shared; } 

    @Override() 
    public void run() { 
    System.out.println(shared.get()); 
    } 

} 

这将打印2,因为主要方法是确保线程顺序运行。在更现实的方法中,线程将同时启动,并且根据相对时序打印0,1或2。

+0

对于我的代码,我感到很遗憾,它的意思有点像伪代码,我认为它足够清晰,我的意思是它。 但后来我正确理解,如果每个类创建一个对象,他们不会使用相同的int。 你说传球的对象,有没有其他的选择? –

+0

谢谢你的回答我很清楚,但我想我会依靠atm的传递。 –

+0

@AllanPedersen重要的是线程之间共享的对象对于并发访问必须是安全的。这意味着不仅应该对共享对象进行多重修改,而且还要确保内存屏障保证了其他线程可以看到更改。使用不可变对象或使用并发队列在标识点处将对象从一个线程显式传递到另一个线程是比较安全的,而不是让任何一个对象在任何时候都可以异步修改。 – erickson

1

在控制台中看到的东西(假设某些实例化C并将它传递给执行它的线程)将为0,因为没有其他任何内容正在写入该实例A.a是run方法的局部变量,没有别的东西可以看到它。

多线程访问是指对象在线程之间传递时。一个典型的例子是一个队列,其中有不同的线程写入数据结构,其他线程从相同的数据结构中删除对象。 写入队列(生产者)的每个线程都会创建对象并将其放入队列中。相同的对象将被不同的线程(称为消费者)检索,这些线程致力于从队列中取出对象并对它们执行某些操作。所以一个生产者创建的对象被放置在队列中,并保持在那里,直到被消费者占用。

这是一个简单的队列实现。它使用​​锁定内部列表,以便一次只有一个线程可以访问队列。

public class MyQueue<T> { 

    private List<T> list = new ArrayList<T>(); 

    public T take() throws InterruptedException { 
     synchronized(list) { 
      while (list.size() == 0) { 
       list.wait(); 
      } 
      return list.remove(0); 
     } 
    } 

    public void put(T object) { 
     synchronized(list) { 
      list.add(object); 
      list.notifyAll(); 
     } 
    } 
} 
+0

这应该是被接受的答案。队列最可靠的是OP所指的。 – Chisx