0

I'm not trying to fill the board with another of the same question, but I read about 15 solutions and nobody has quite the same issue. Here is the code I am looking at:

private AgentModel agent;
private UserModel user;
private int type;

public AgentThread(AgentModel agent, UserModel user, int type) {
    this.agent = agent;
    this.user = user;
    this.type = type;
}

public void start() throws InterruptedException {
    agent.setT(new Thread(this, agent.getID()));
    agent.getT().start();
}

And a little bit down the way:

public void run() {
    while (!agent.getT().isInterrupted()) {
        agent.nextOP();

        try {
            if (agent.getOPS() > 0) {
                agent.getT().sleep((long) (1000 / agent.getOPS()));
            } else {
                agent.getT().sleep(1000);
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            agent.getT().interrupt();
        }
        synchronized (user) {
            agent.setState(agent.getT().getState().toString());
            // System.out.println("Operations Completed: " +
            // (1+agent.getOPCompleted()) );
            if (type == 3) {
                user.deposit(agent.getAmount(), Integer.valueOf(agent.getID()));
            }
            if (type == 4) {
                user.withdraw(agent.getAmount(), Integer.valueOf(agent.getID()));
            }
        }
    }
}

The agent object contains a thread that is started in the AgentThread start method. The AgentThread object takes in both the agent and the user and instances of their respective classes.

My problem is as follows: I'm setting the lock to be the instance of the UserModel class 'user'. The threads are supposed to either deposit or withdraw depending on their agent type.

When I execute agent.getT().getState(), it always returns RUNNABLE no matter how many instances of AgentThread I have created. Each AgentThread is given a new agent and a new thread but the same User object. It seems as though the threads are never blocking each other.

I know they are influencing the same user instance because I can output the changes detected by my listener and it reflects all running threads and their interactions with that user instance.

Every time a thread is started it enters an "infinite" loop where the user instance has a deposit or a withdrawal. These actions happen every x seconds.

BKreger
  • 89
  • 1
  • 1
  • 11
  • There's a lot of code you aren't showing us, but out of curiosity, how much time do you expect a thread to spend in any one pass through that `synchronized` block? It could be mere microseconds. You say, "No matter how many instances of `AgentThread` I have created," but how many instances is that? How often do they enter the `synchronized` block? And, how often does your program ask for a thread's state? What I'm really trying to get at here is, what reason do you have to think that there will be so much contention for that lock that you would be likely to notice it? – Solomon Slow Apr 29 '16 at 17:26
  • @james large I have had 4 instances running at once, all enter the block pretty quickly and the program asks the threads state every pass through the block – BKreger Apr 29 '16 at 17:34
  • @mastov how would I detect if the thread has been blocked outside of checking its state? – BKreger Apr 29 '16 at 17:36
  • @mastov I see, so more than likely the synchronized block is working properly I am just not able to determine that through the state property of the thread...bummer – BKreger Apr 29 '16 at 17:39
  • @mastov, If a thread is blocked by contention for a mutex, then its state _will_ be `BLOCKED`. And, that's useful information, because if you can ever catch a thread in that state, it probably means that your threads are spending too much time in the mutex. – Solomon Slow Apr 29 '16 at 17:46
  • @jameslarge So ultimately I need to be able to display in the operator window whether or not the current thread is blocked, running, or stopped. This is why I was checking the state directly. I guess i am not understanding how even when accessing the same object they do not block each other? – BKreger Apr 29 '16 at 17:46
  • If two threads try to enter the `synchronized(user)` block at the same time, then you have a _data race_, and the loser of the race _will_ be `BLOCKED` until the winner gets in and back out. You still haven't said why you think it would take more than a microsecond for the winner to get in and out. The names of the methods that you call from within the synchronized block make it seem as if they are all very trivial---getters and setters mostly. – Solomon Slow Apr 29 '16 at 17:50
  • P.S., Getting in and out of a `synchronized(...)` block is a _good_ thing. One of the most important rules-of-thumb for multi-threaded programming is to keep your mutexes as small as possible (but, no smaller!) – Solomon Slow Apr 29 '16 at 17:52
  • 1
    @jameslarge Well its not that I expect them to ever reach a blocked state, but it seemed to me that there would be at least some point in time where they would block. However when you put it into perspective I imagine they never would really block each other or at least the chances would be extremely low for me to notice it happen so quickly. – BKreger Apr 29 '16 at 17:55

2 Answers2

0

You threads only lock the User object for enough time to perform a deposit() or withdraw() operation at intervals of, probably, hundreds of milliseconds. Unless deposit() or withdraw() are dependent on high latency external resources, they probably execute in a fraction of a microsecond, which would be enough for, say, thousands of lines of code. As a result, your chances of catching the system in a state where a thread has the User object locked are probably less than 1 in 100,000. In addition, for another thread to be blocked, it too would need to be trying to perform a deposit() or withdraw() operation. Given your likely parameters, the chances of such a collision are less than one in a million, which likely explains why you've never seen it.

Warren Dew
  • 8,790
  • 3
  • 30
  • 44
0

When I execute agent.getT().getState(), it always returns RUNNABLE no matter how many instances of AgentThread I have created.

Right. This is because you are calling the agent.getT().getState() from inside of the thread itself. The thread will always see itself as RUNNABLE. When it is blocked or waiting, it isn't looking.

It seems as though the threads are never blocking each other.

No, as I read the code they are certainly blocking each other if they are working on the same User object. However, you are never calling agent.getT().getState() from another thread so it can see the BLOCKED or WAITING states.

One way to look at thread externally is by turning on JMX and using jconsole. If you go to the threads tab, you should be able to see the "Total blocked" and "Total waited" counts increase on your worker threads.

Every time a thread is started it enters an "infinite" loop where the user instance has a deposit or a withdrawal. These actions happen every x seconds.

I assume that's what you are expecting.

Community
  • 1
  • 1
Gray
  • 115,027
  • 24
  • 293
  • 354