我'我正在学习多线程,对于一些事情我有点困惑,
例如
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();
}
}
现在我无法显示图像,但我想明确我的配音
如果我开始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(); |
--------------------------------- --------------------------------
我的意思是,每个线程都有自己的流程(他自己&#34;复制&#34; of function1 ),完成后他们将等待执行锁定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()
?
执行顺序将始终受到尊重,首先是function1和function2?
对不起,如果这么久,无论如何都要提前感谢。
答案 0 :(得分:4)
synchronized关键字不会锁定函数,而是锁定对象,这意味着两个线程不能同时使用同一个对象。 <{1}}只是
的语法糖synchronized void function2
同步(即锁定对象)的原因是没有线程可以在其不变量被破坏的状态下看到对象。在您的示例中,类void function2(){synchronized(this){//
没有状态,因此没有不变量,这意味着您不需要锁定它。
您似乎关注的是Example
的局部变量。但是,局部变量永远不会在线程之间共享,因此每个线程都有自己的每个局部变量的实例。
附录:根据用户 hexafraction 的建议,需要同步的示例:
考虑以下简单类:
function2
这个类是可变的;其状态由public class Example {
public int count = 0;
public void increment() {
count++;
}
public void decrement() {
count--;
}
}
的值定义。如果客户端调用count
或increment
,则状态应该更改。两种方法都有契约:
decrement
必须保证increment
的值是count
的旧值加1。我们用count
Simliarly,count = old(count) + 1
的合约是decrement
让我们依次运行这个课程:
count = old(count) - 1
打印:
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
的同一实例的线程:
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);
}
上拨打increment
和decrement
两次。但现在,结果完全不确定。多次运行代码,打印的数字可能是:sharedData
。
这怎么可能?我们总是添加一个或减去一个,但在完成1000次后,我们应该得到值0,对吗?问题是一个线程可能对另一个线程的更改无知。请注意16, -76, 138, -4
不是原子的;它与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
关键字。我们可以通过锁定实例来禁止对synchronized
的共享实例进行并发修改。所以我们修改我们的课程:
Example
让两个方法锁定实例很重要,因为两个方法都不能看到处于不一致状态的对象。
如果我们无法修改public class Example {
public int count = 0;
public synchronized void increment() {
count++;
}
public synchronized void decrement() {
count--;
}
}
的代码,例如,因为它是我们使用的库的一部分,该怎么办?我们如何使用Example
关键字来使用多个线程的代码?如前所述,synchronized
与synchronized void increment(){
相同,因此同步不是方法的属性,而是对象的属性。保留void increment(){synchronized(this)
的代码不变,我们可以改变我们的客户端:
Example
答案 1 :(得分:0)
由于你同时制作了function1
和function2
synchronized
没有线程可以在执行结束之前留下它们,所以一个线程无法停止function1和另一个线程的中间执行其function1或function2。但是请注意,如果两个线程中都存在相同的run()
方法(我猜是这样),而第一个完成function1
,则调度程序或调度程序可以停止它并运行thread2,它可以完成两个函数调用,然后thread1可以继续。
注意:使用methods()而不是函数()。