2014-11-03 74 views
0

我是学习多线程,我有点困惑的几件事情,多个线程访问方法

例如

public class Example{ 

    public void function1(){ 
     int toPrint = 0; 
     System.out.println(toPrint); 
     for(int i = 0; i < 10; i++) 
     System.out.println("hello stackOverflow!"); 
    } 
    public syncrhonized void function2(){ 
     ... 
    } 

} 

public static void main(String[] args) { 
      Example example = new Example(); 
      for (int i = 0; i < 10; i++) { 
       RunningThread thread = new RunningThread(example); 
       thread.start(); 
      } 
     } 

像这样

public class RunningThread{ 
    Example instanceClass; 
    public RunningThread(Example instanceClass){ 
    this.instanceClass = instanceClass; 
    public void run(){ 
     while(true){ 
      instanceClass.function1(); 
      instanceClass.function2(); 
     } 
    } 

现在循环我不能显示图像,但我想在我的dubts清楚,所以

如果我开始N个线程,我必须打算这种情况

_______________________________   ______________________________ 
|    thread1   |  |   thread..N   | 
.................................  ................................ 
|   function1   |  |   function1   | 
|   int toPrint = 0;  |  |  int toPrint = 0;  | 
| System.out.println(toPrint); |  | System.out.println(toPrint);| 
| for(int i = 0; i < 10; i++) |  | for(int i = 0; i < 10; i++) | 
| System.out.println();  |  |  System.out.println(); | 
---------------------------------  -------------------------------- 

什么,我的意思是说,每个线程都有自己的流量(的功能1自己的“副本”),并整理他们将等待执行锁定function2()后?

_______________________________   
|  thread1 and thread..N |  
.................................  
|   function1   |  
|   int toPrint = 0;  |  
| System.out.println(toPrint); |  
| for(int i = 0; i < 10; i++) |  
| System.out.println();  |  
--------------------------------- 

在这种方式的每个线程shares相同的功能和内容(因此,例如一个线程初始化值和另一个线程不进行初始化)和精加工后,他们将等待执行锁定的function2()

的执行顺序将始终尊重,第一功能1和功能2?

不好意思,如果这么长,反正先谢谢了。

+0

我在代码中看不到任何线程。此外,我没有看到多个线程调用'function2'。 – 2014-11-03 13:12:59

+0

请给我们显示完整的代码。 – TheLostMind 2014-11-03 13:13:32

+0

等待,我会插入当我开始线程,但我认为这是次要的... – user582040 2014-11-03 13:14:29

回答

4

synchronized关键字不锁定功能,但对象,这意味着两个线程不能同时使用相同的对象。 synchronized void function2只是语法糖

void function2(){synchronized(this){// 

的原因进行同步,即,锁定的对象是没有线程可以看到一个对象的状态下,它的不变量是断开的。在你的例子中,类Example没有状态,因此没有不变量,这意味着你不需要锁定它。

你似乎什么都是function2局部变量予以关注。但是,局部变量永远不会在线程之间共享,因此每个线程都有自己的每个局部变量的实例。


附录:如所建议的通过用户hexafraction,其中需要同步的一个示例:

考虑以下简单的类:

public class Example { 
    public int count = 0; 

    public void increment() { 
     count++; 
    } 

    public void decrement() { 
     count--; 
    } 
} 

这个类是可变的;其状态由值count定义。如果客户拨打incrementdecrement,那么状态应该改变。这两种方法有合同要坚持:

  • increment必须保证的count的值是count加上一个旧值。让我们count = old(count) + 1

  • Simliarly表示此合同,decrement合同是count = old(count) - 1

我们来运行这个类sequentally:

public static void main(String[] args) { 
    Example sharedData = new Example(); 
    for (int i = 0; i < 1000; i++) 
     sharedData.increment(); 
    System.out.println("Incrementer finished"); 
    for (int i = 0; i < 1000; i++) 
     sharedData.decrement(); 
    System.out.println("Decrementer finished"); 
    System.out.println(sharedData.count); 
} 

它打印:

Incrementer finished 
Decrementer finished 
0 

我们可以像w一样运行代码如果想要,结果将始终如一。

让我们定义使用Example同时相同的实例多线程:

public static void main(String[] args) throws InterruptedException { 
    Example sharedData = new Example(); 
    Thread incrementer = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      for (int i = 0; i < 1000; i++) 
       sharedData.increment(); 
      System.out.println("Incrementer finished"); 
     } 
    }); 
    Thread decrementer = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      for (int i = 0; i < 1000; i++) 
       sharedData.decrement(); 
      System.out.println("Decrementer finished"); 
     } 
    }); 
    incrementer.start(); 
    decrementer.start(); 
    incrementer.join(); 
    decrementer.join(); 
    System.out.println(sharedData.count); 
} 

我们现在有两个线程:一个增量和递减器。代码看起来有点不同,但我们可能期望它达到相同的结果。再次,我们在共享的sharedData上拨打incrementdecrement两次1000次。但是现在,结果是完全不确定的。多次运行代码,打印的数字可能是:16, -76, 138, -4

这怎么可能?我们总是增加一个或者减少一个,但是在两次1000次之后,我们应该有0的值,对吧?问题是一个线程可能对另一个线程的改变无知。请注意,count++不会发生原子;它与count = count + 1相同,它由读,计算和写组成。

考虑以下顺序历史:

incrementer enters increment and reads the value of count, count == 0 
decrementer enters decrement and reads the value of count, count == 0 
incrementer adds one and modifies the state, count == 1 
decrementer subtracts one and modifies the state, count == -1 

注意,通过decrementer计算的状态变化是基于count的价值,它读取,即0,这意味着它没有看到状态变化由incrementer完成。

有多种方法可以解决此问题,但让我们试试​​关键字。通过锁定实例,我们可以禁止共享Example实例的并发修改。因此,让我们修改我们的类:

public class Example { 
    public int count = 0; 

    public synchronized void increment() { 
     count++; 
    } 

    public synchronized void decrement() { 
     count--; 
    } 
} 

有两种方法锁定实例是非常重要的,因为这两种方法不能看到处于不一致状态的对象。

如果我们无法修改Example的代码,例如因为它是我们使用的库的一部分,该怎么办?我们如何才能使用​​关键字来使用多线程的代码?如前所述,synchronized void increment(){void increment(){synchronized(this)相同,所以同步不是方法的属性,而是对象。离开Example的代码不变,我们可以改变我们的客户端:

public static void main(String[] args) throws InterruptedException { 
    Example sharedData = new Example(); 
    Thread incrementer = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      for (int i = 0; i < 1000; i++) 
       synchronized (sharedData){ 
        sharedData.increment(); 
       } 
      System.out.println("Incrementer finished"); 
     } 
    }); 
    Thread decrementer = new Thread(new Runnable() { 
     @Override 
     public void run() { 
      for (int i = 0; i < 1000; i++) 
       synchronized (sharedData){ 
        sharedData.decrement(); 
       } 
      System.out.println("Decrementer finished"); 
     } 
    }); 
    incrementer.start(); 
    decrementer.start(); 
    incrementer.join(); 
    decrementer.join(); 
    System.out.println(sharedData.count); 
} 
+0

您应该添加一个示例,其中多个方法具有'synchronized'关键字。 – hexafraction 2014-11-23 16:53:36

+1

@hexafraction感谢您的反馈。我保留最初的答案,但在两个同步非常重要的方法中增加了一个示例(和解释)。 – 2014-11-24 01:28:19

0

既然你做既function1function2​​没有线程可以离开他们之前执行结束,所以没有办法一个线程在功能1的中间停止,而另一个线程执行其功能1或函数2。但是千万注意,如果同一run()方法有两个线程(这是我猜的),而第一完成function1调度员或调度可以停止和运行线程2,可同时完成这两个函数调用,然后thread1可能会继续。

注意:使用方法(),而该功能()。