私有变量是否安全

时间:2016-02-14 05:49:09

标签: java multithreading thread-safety concurrentmodification

当两个线程试图修改对象的数据时,开发api的开发人员(比如java中的Collections api)是否应该手动抛出ConcurrentModificationException?

为什么这段代码不会抛出异常,因为多个线程试图修改Person对象的内容?

public class Main {

    public static void main(String[] args) {
    // write your code here
        RunnableDemo r = new RunnableDemo();
        for (int i = 0; i < 10; i++) {
            Thread t = new Thread(r, "Thread " + i);
            t.start();
        }
    }
}

class RunnableDemo implements Runnable {

    private Person person = new Person();

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            person.setName("Person" + i);
            System.out.println(person.getName());
        }
    }
}

class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

4 个答案:

答案 0 :(得分:1)

当你认为必须时,你应该抛出异常。当两个线程同时尝试修改person对象时,你的代码不会抛出异常,但在这种情况下你可能会得到不可预测的结果,你应该手动防止并发修改。

答案 1 :(得分:0)

如果你希望你的类抛出ConcurrentModificationException,那么你必须编写抛出它的代码。

Java不会抛出ConcurrentModficationException,因为两个线程试图同时更新同一个对象。实际上,Java 从不抛出ConcurrentModificationException.

某些标准的Java 库类会在注意到对象处于错误状态时抛出异常,而该状态只是由调用者违反规则引起的。

例如,某些容器类的Javadoc表示在迭代容器时不允许修改容器。如果您的代码获得迭代器,然后更新容器,然后调用iterator.next(),当next()调用注意到容器不再处于与此时相同的状态时,ConcurrentModificationException调用将抛出 public T next() { if (...the container has been modified...) { throw new ConcurrentModificationException(...); } ... } 迭代器已创建。

在这种情况下抛出是明确的。它并不是出自Java的核心:它位于容器类的源代码中。如果您查看该类的源代码,您会看到类似的内容:

public int this[int index]    
{
    // get and set accessors
}

如果您希望您的课程抛出该异常,那么您必须编写一些类似的代码。

答案 2 :(得分:-1)

让我们及时了解这一步 对于初学者,我会尝试回答几个可能已经克服的问题。

a)您是否在创建多个主题?
即可。是的,确定,您正在创建101个逻辑线程(1个主线程+ 100个其他通过调用线程的start()方法)。逻辑上我的意思是没有实际的100个并行线程,而是映射到核心内核线程(基本上是核心数)。

每个核心都有一个工作队列,逻辑线程被分配给核心。可能会发生这种情况(比如在双核机器中),其中一个核心忙着处理某个任务,所有应用程序线程(由程序创建)都映射到同一个核心。

JVM决定如何映射线程以及调度逻辑线程及其执行时间。

b)调用start()会发生什么?
Ans。有关线程生命周期的精确概述,请访问:http://www.javatpoint.com/life-cycle-of-a-thread

要突出显示,调用start()方法不会使线程处于运行状态。它必须由Thread调度程序拾取才能进入该状态。因此,并非程序启动的所有线程实际上可以并行运行。

c)那么这里发生了什么呢?
Ans。在您的情况下,任务非常小,以至于JVM决定在调度另一个线程之前放弃一个线程。因为根据JVM,如果它没有这样做,很多时间将浪费在获取和释放CPU资源上,因此在上下文切换中浪费了大量时间。

你的一般解释。

- 你在这里理解错了什么?
Ans。要获得异常,必须首先抛出异常。整个代码不会产生异常。

您正在将&#34; name&#34; 设置为每个线程的新引用,而不是修改String的状态(实际上在JAVA中是不可变的)。

当两个线程试图修改对象的数据时,正在开发api的开发人员(比如java中的Collections api)是否应该手动抛出ConcurrentModificationException?
Ans。如果状态可以被多个线程修改并且可能影响用户查看相应的数据状态,则无权成为线程安全的API应抛出 ConcurrentModificationException 结构(如ArrayList,HashMap等)

答案 3 :(得分:-1)

/*
 * Thread-Safe Example in Java
 */
public class Counter {

    private int count;
    AtomicInteger atomicCount = new AtomicInteger( 0 );


    /*
     * This method thread-safe now because of locking and synchornization
     */
    public synchronized int getCount(){
        return count++;
    }

    /*
     * This method is thread-safe because count is incremented atomically
     */
    public int getCountAtomically(){
        return atomicCount.incrementAndGet();
    }
}

了解详情:http://javarevisited.blogspot.com/2012/01/how-to-write-thread-safe-code-in-java.html#ixzz4z8Rx4P2Y