java setter位于父对象上时子对象上的线程安全

dy1byipe  于 2023-10-14  发布在  Java
关注(0)|答案(3)|浏览(95)

下面的示例代码在多线程环境中是否是线程安全的,当创建一个新的Child对象时,其中一些setter位于父对象上。

public abstract class ParentClass {
   private String familyName;

   public Strng getFamily() {
     return familyName;
   }
   public void setFamily (String familyName) {
    return  this.familyName = familyName
}
public class ChildClass extends ParentClass  {
   private String firstName;

   public String getFirstName() {
     return firstName;
   }
   public void setFirstName (String firstName) {
    return  this.firstName = firstName
}

现在,当我创建一个新的子对象时,如下所示,当子对象在应用程序中处理时,setter(setFamily)是否是线程安全的

var child = new ChildClass()
child.setFirstName("Jo");
child.setFamilyName("Smith");
r7knjye2

r7knjye21#

Inheritancethread-safety是正交主题。
代码:

var child = new ChildClass()
child.setFirstName("Jo");
child.setFamilyName("Smith");

.是线程安全的,如果所有三行都在同一个线程中执行。
线程安全问题源于共享资源。这些资源包括可能被修改的共享文件、共享网络连接或共享可变变量。
在本例中,您有一个ChildClass的新示例。作为新的意味着它是,到目前为止,未与任何其他线程共享。您可以通过同一线程中同一示例上的setter方法访问其包含的字段-因此没有其他线程意味着没有跨线程共享的资源,这意味着没有线程安全问题。
在子类上定义两个setter,而在超类上定义另一个setter,这一事实并不影响线程安全性。您可以将这两个类看作是合并的,超类内容折叠到子类中。
就线程安全性而言,定义所有三个setter的单个类与一个定义两个setter而另一个定义单个setter的一对类之间没有区别。
如果你开始跨线程调用这些getter和setter,那么你将遇到线程安全问题。

q3aa0525

q3aa05252#

var child = new ChildClass()
child.setFirstName("Jo");
child.setFamilyName("Smith");

从技术上讲,这些行是线程安全的,因为child引用的对象是 * 线程限制的 *;即,它只能从一个线程访问。
如果另一个线程可以访问child示例,那么整个应用程序就不是线程安全的。(这有一些复杂的例外,但我们不要去那里。
但是,类本身不是线程安全的。方法在超类或子类中的位置对线程安全性没有影响。如果你希望这些类是无条件线程安全的,那么你需要添加一些显式的同步机制,或者将它们重写为不可变的类。
请注意,线程安全性在技术上很难用精确的术语定义。一种方法是从功能正确的代码开始(根据一些指定的要求),当只使用一个线程执行时。如果代码对于涉及多个线程的所有可能的执行都是功能正确的,那么代码是线程安全的。
因此,如果我们要问XYZ类是线程安全的,我们首先需要XYZ需要满足的规范。在你的示例类中,我们可以推断出一个规范,该规范规定getter返回相应setter最近设置的值。根据该规范,您的类不是线程安全的,因为缺乏同步意味着可能存在内存异常。但是将getter和setter声明为synchronized方法对于该规范的线程安全性来说已经足够了。

t2a7ltrp

t2a7ltrp3#

这两个类都不是线程安全的。你必须使用同步机制来实现线程安全。
1.你可以在父类的getter和setter中使用synchronized关键字。
1.或者你可以使用其他同步机制来实现线程安全,如ReentrantLock或Semaphores。
你能详细说明一下吗?
只是放了一个示例代码,使用信号量实现线程安全。

import java.util.concurrent.Semaphore;

public abstract class ParentClass {
  private String familyName;
  private final Semaphore semaphore = new Semaphore(1); // Initialize with one permit

  public String getFamily() {
    return familyName;
  }

  public void setFamily(String familyName) {
    try {
        semaphore.acquire(); // Acquire the permit
        this.familyName = familyName;
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    } finally {
        semaphore.release(); // Release the permit
    }
  }
 }

public class ChildClass extends ParentClass {
  private String firstName;

  public String getFirstName() {
    return firstName;
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
}

这确保了一次只有一个线程可以修改familyName,使其成为线程安全的。

相关问题