Aceso
Aceso

Reputation: 1215

Multithread programming and incrementing a static variable

I have read almost all posts related to my problem but could not solve my problem. this code is a question in the Big Java - Early Object of Cay Horstmann. The question asks about counting the word of several files by using multithread programming and store the combined words counting which is my problem.

in order to get the combined counter I used a static variable which is incremented on each of iteration of counting words in threads. Also I used a ReentrantLock() to make incrementing available only for one thread at a time. everything works fine except incrementing. it seems sometimes the static variable does not incremented. I tested the number of lock() and unlock() by each thread and they match with my expected result however the static variable does not work properly.

is there any explanation for it? thank you for your time and help.

my task class:

 import java.io.File;
 import java.io.FileNotFoundException;
 import java.util.Scanner;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;

public class WordCount implements Runnable
{
    private String fileName;
    Scanner inputFile;
    private long counter;
    public volatile static long combinedCounter = 0;
    Lock ccLock;

    public WordCount(String aName) throws FileNotFoundException
    {
        try
        {
            this.ccLock = new ReentrantLock();
            this.counter = 0;
            this.fileName = aName;
            this.inputFile = new Scanner(new File(this.fileName));
        }
        catch (FileNotFoundException e)
        {}
     }
    public void cCount()
    {
        ccLock.lock();
        try
        {
            combinedCounter++;
            /*synchronized (this)
            {
                combinedCounter++;
            }*/
         }
        finally
        {
            ccLock.unlock();
        }
     }
    @Override
    public void run()
    {
        try
        {
            while (inputFile.hasNext() && !Thread.interrupted())
            {
                 synchronized (this)
                 {
                     cCount();
                 }
                 counter++;
                 inputFile.next();
                 Thread.sleep(0);
             }
             System.out.printf("%s: %d\t\t%d\n", this.fileName,           
             this.counter,combinedCounter);
        }
         catch (InterruptedException e)
         {}
     }
 }

This is my client class:

    import java.io.FileNotFoundException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;

    public class WordCountRunner
    {

        public static void main(String[] args) throws FileNotFoundException,
                InterruptedException
        {
            String a = "a.txt";
            String b = "b.txt";
            ExecutorService pool = Executors.newFixedThreadPool(2);
            ;
            try
            {
                Runnable r1 = new WordCount(a);
                Runnable r2 = new WordCount(b);
                pool.execute(r1);
                pool.execute(r2);

                while (!pool.isTerminated())
                {
                    pool.shutdown();
                }
                Thread.sleep(100);
                System.out.print("***" + WordCount.combinedCounter);
            }
            catch (FileNotFoundException e)
            {

            }
            finally
            {
                pool.shutdown();

            }
        }

    }

Upvotes: 0

Views: 555

Answers (2)

schtever
schtever

Reputation: 3250

The lock does not work because the ReentrantLock is an instance variable in the WordCount class. So, each instance of that class has its own private lock and they don't synchronize with each other. The easiest change would be to make the lock static, like the variable it's protecting.

Upvotes: 4

John Bollinger
John Bollinger

Reputation: 180181

Each of your Runnables has its own lock object. For your strategy to work, they all need to share exactly one lock.

For example,

    // ...
    static Lock ccLock = new ReentrantLock();

    public WordCount(String aName) throws FileNotFoundException
    {
        try
        {
            // this.ccLock = new ReentrantLock();
            this.counter = 0;
            this.fileName = aName;
            this.inputFile = new Scanner(new File(this.fileName));
        // ...
    }

Upvotes: 2

Related Questions