gpt4 book ai didi

java - 多线程访问方法

转载 作者:行者123 更新时间:2023-12-01 18:24:23 25 4
gpt4 key购买 nike

我正在研究多线程,我对一些事情有点困惑,

例如

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(); |
--------------------------------- --------------------------------

我的意思是,每个线程都有自己的流程(他自己的函数1的“副本”),完成后它们将等待执行锁定的函数2( )

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

通过这种方式,每个线程共享相同的功能和内容(例如,一个线程初始化该值,另一个线程初始化该值)不初始化它)完成后他们将等待执行锁定的function2()

执行顺序将始终受到尊重,首先是 function1,然后是 function2?

抱歉,如果这篇文章太长了,无论如何,先谢谢了。

最佳答案

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

  • 表示此合约
  • 同样,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

我们可以根据需要运行代码,结果总是相同的。

让我们定义多个线程,它们同时使用类示例同一个实例:

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,这意味着它没有看到增量器完成的状态更改。

有多种方法可以解决这个问题,但让我们尝试一下 synchronized 关键字。我们可以通过锁定实例来禁止对 Example 的共享实例进行并发修改。所以让我们修改我们的类:

public class Example {
public int count = 0;

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

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

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

如果我们无法修改示例的代码(例如,因为它是我们使用的库的一部分)怎么办?我们如何使用synchronized关键字让多个线程使用代码?正如已经提到的,synchronized voidincrement(){voidincrement(){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);
}

关于java - 多线程访问方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26715070/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com