Hello I have a project for school where I must create a program in java that counts the words in one or more files. It should start a new thread for each new file. Its also supposed to have locks to protect the combined word counter and a counter for active threads. Ive tried researching locks, but im having trouble grasping the concept.
Here is what I was able to come up with so far.
public class Main {
public static void main(String[] args)throws InterruptedException {
WordCount[] counters = new WordCount[args.length];
for (int index = 0; index < args.length; ++index)
{
counters[index] = new WordCount(args[index]);
counters[index].start();
}
int total = 0;
for (WordCount counter : counters)
{
counter.join();
total += counter.count;
}
System.out.println("Total:" + total);
}
}
public class WordCount extends Thread {
int count;
#Override
public void run()
{
count = 0; //it will count the words
++count;
}
}
'Protecting' the word counter really just means preventing two threads from attempting to update the word counter at the same time. The simplest way to achieve that in Java is with the synchronized keyword:
class WordCounter {
private int count = 0;
public synchronized void incrementCount() {
count++;
}
}
Now if two threads call that method the JVM will force one to wait until the other completes.
Next you need a method that will count words in a file. That should be relatively simple. Something like:
private void countWords(Path path) {
for (String line : Files.readAllLines(path)) {
for (String word : line.split("\\s+")) {
counter.incrementCount();
}
}
}
You'll need to cope with IO exceptions here.
Finally you need to create a thread for each file. At the moment you are subclassing the Thread class but a simpler solution is just to create a thread with the Runnable you need the thread to run:
for (Path path: myFiles) {
Thread thread = new Thread(() -> counter.countWords(path));
thread.run();
}
That's about it. I haven't added the code to keep a running thread count but it really just follows the same pattern.
Related
This question already has answers here:
Thread safety in java multithreading
(3 answers)
Difference between volatile and synchronized in Java
(4 answers)
Closed 1 year ago.
My problem is that the code should increment a 1000 times and then output it. But sometimes a isn't 1000 at the end.
public class Counter extends Thread {
private static Integer a = 0;
public void run() {
for (int i = 0; i < 100; i++) {
a++;
}
}
public static void main(String[] args) {
Counter[] ca = new Counter[10];
for (int i = 0; i < 10; i++) {
ca[i] = new Counter();
ca[i].start();
}
for (Counter c : ca) {
try {
c.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(a);
}
This code is the original code that is obviously not going to work because I have multiple Threads accessing the variable a. I've tried putting a synchronized(this) around a++; and marking a as volatile but I still sometimes get a false Result. The only way I've found to make it work reliably it to put join() into the for loop, but that kind of defeats the point of using Threads in the first place.
Any help is appreciated.
There are several problems in the code you posted, and all them a reported in the comments to your qestion.
I try to show the major ones:
Variable a is Integer which is immutable, this means that a++ really means create a new Ineger instance containing the old value plus 1.
the variable a is updated by multiple threads concurrenlty without synchonizazion, this means that the operation a=a+1 canbe split in read a, increment a; if two or more thread read a at the same time the the increment by one the same value
Here is a modified version that uses a Lock to synchronize access to the resource. The main scope of this code is to show that the access to a must be synchronixed between thread; in order to get a "clean design" you must refactor/change a lot of other things.
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SyncProblem {
private static int a=0;
private static class IncThread extends Thread {
private Lock lock;
public IncThread(Lock lock) {
this.lock=lock;
}
public void run() {
lock.lock();
try {
for (int i = 0; i < 100; i++) {
a++;
}
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
Lock lock= new ReentrantLock();
IncThread[] ca = new IncThread[10];
for (int i = 0; i < 10; i++) {
ca[i] = new IncThread(lock);
ca[i].start();
}
for (IncThread c : ca) {
try {
c.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(a);
}
}
I am having trouble figuring out what my code is doing as this is my first time coding using multiple threads. To start off, in attempt to learn this type of programming I decided to write a miniature program that uses 8 threads to sum a number. However, no matter what I do it seems as if my program never stops when count = 10, it continues onward. I am using 8 threads as I planned on expanding my program to do large calculations. However, these threads are not correlating at all. They are going way past 10. I have used a synchronized method. I have tried a lock. I have tried implementing both at the same time. No matter what, it appears as if the threads still calculate past 10. See below for my current code.
public class calculator implements Runnable {
static int counter = 0;
static int sum = 0;
private synchronized static int getAndIncrement()
{
// System.out.println("counter is : " + counter);
int temp = counter;
counter = counter + 1;
System.out.println("counter is now : " + counter);
return temp;
}
private synchronized void addToSum(int value)
{
// System.out.println("sum : " + sum + " value: " + value);
sum += value;
}
#Override
public void run()
{
// TODO Auto-generated method stub
while(counter < 10)
{
int tempVal = getAndIncrement();
System.out.println("temp val : " + tempVal);
addToSum(tempVal);
// System.out.println("sum is now : " + sum);
}
}
}
This is my main method:
public static void main(String[] args)
{
calculator[] calc = new calculator[8];
Thread[] thread = new Thread[8];
final long startTime = System.currentTimeMillis();
for(int i = 0; i < 8; i++)
{
calc[i] = new calculator();
thread[i] = new Thread(calc[i]);
thread[i].start();
}
while(thread[0].isAlive() ||thread[1].isAlive() || thread[2].isAlive() || thread[3].isAlive() || thread[4].isAlive() || thread[5].isAlive() || thread[6].isAlive() || thread[7].isAlive())
{}
final long endTime = System.currentTimeMillis();
System.out.println(calculator.sum);
System.out.println("Execution time : " + (startTime - endTime));
}
I appreciate the help!
The synchronized keyword takes the object
lock. This means that two methods that are synchronized cannot execute on the same object. They will, however, execute concurrently on invocation on 2 different objects.
In your example, your code had 8 objects of calculator. The synchronized methods do not help you. Each thread uses it's separate object. You can completely remove the synchronized keyword, and your code will be semantically equivalent.
To avoid this, use the atomic version of the objects (AtomicInt) or lock on the objects themselves: synchronized(counter){...} but for this to work you will have to change the type to Integer.
I've just tested your sample and found the addToSum method doesn't work as expected here with heavy multi-thread, even if synchronized keyword is present.
Here, as sum variable is static, the method can be made static too.
After adding the static keyword, the behavior is as expected:
private static synchronized void addToSum(int value)
{
sum += value;
}
Here a simple test (addToSum replaced by incSum for simplicity) :
class IncrementorThread implements Runnable {
private static int sum = 0;
private static synchronized void incSum()
{
sum ++;
}
public void run() {
incSum();
Thread.yield();
}
}
void testIncrementorThread1() {
ExecutorService executorService = Executors.newCachedThreadPool();
//ExecutorService executorService = Executors.newSingleThreadExecutor() // result always ok without needing concurrency precaution
for(int i = 0; i < 5000; i++)
executorService.execute(new IncrementorThread());
executorService.shutdown();
executorService.awaitTermination(4000, TimeUnit.MILLISECONDS);
System.out.println("res = "+IncrementorThread.sum); // must be 5000
}
Result must be 5000, which is not the case if we remove the static keyword from the method incSum()
This question already has answers here:
Synchronization on immutable objects (in java)
(4 answers)
Closed 6 years ago.
I'm new to java and was trying out synchronization with a sample program to add numbers upto 100 using multiThreading. And following is code i was able to come up with. When i test the code it sometimes gives the correct value of 4590 but sometimes doesnt give the correct value. Can anyone point out what i'm doing wrong
class Counter{
Integer counter = 0;
public void increment(int i){
synchronized (counter){
counter += i;
}
}
}
class ObjectTest implements Runnable{
int i;
Counter blah;
public ObjectTest(Counter counter,int i){
blah =counter;
this.i = i;
}
#Override
public void run() {
blah.increment(i);
}
}
public class SyncTest {
public static void main(String args[]) throws InterruptedException {
ThreadPoolExecutor executor = new ThreadPoolExecutor(4,10,60, TimeUnit.SECONDS,new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.CallerRunsPolicy());
Counter counter = new Counter();
for (int index = 0; index < 100; index++) {
ObjectTest objectTest = new ObjectTest(counter,index);
executor.execute(objectTest);
}
executor.shutdown();
while (!executor.isTerminated()){
Thread.sleep(1000L);
}
System.out.println(counter.counter);
}
}
You can't synchronize on counter because it's an Integer, which is immutable. Therefore counter += i creates a new Integer object, which is not the same that was synchronized on.
You can make it int counter and have a separate Object lock = new Object();, synchronizing on lock.
public class MyTest {
ArrayList<Integer> array = new ArrayList<>();
public void initialize() {
//....
}
private void editArray(int num) {
// modified the array
}
public void func(int n) {
for (int i = 0; i < n; i++) {
editArray(i);
}
}
}
I hope to execute "editArray" function in the forloop concurrently, which means n threads(call editArray function) can execute concurrently, how can I do that and add a lock for ArrayList array ? I google a lot, most of tutorials just teach how to spawn thread for different objects. What I want is that spawn thread in a single object.
I mainly want to know how to call a function concurrently in java.
Thanks.
Class C:
class C extends Thread
{
public static int cr;
C(int n)
{
cr = n;
}
public void run()
{
go();
}
synchronized void go()
{
for (int i = 0; i < 10000; i++)
{
cr++;
}
}
}
Class Launch
class Launch
{
public static void main(String args[]) throws InterruptedException
{
C[] c = new C[10];
for (int i = 0; i < 10; i++)
{
c[i] = new C(0);
}
for (int i = 0; i < 10; i++)
{
c[i].start();
}
System.out.println(C.spaces);
}
}
It doesn't give me 100,000, but rather numbers below 100k. Why? I made method go() synchronized, so it should be used by only one thread at a time..? What am I missing?
synchronized void go(){...} means that it is synchronized on current instance (on this). Since this method belongs to your custom Thread class and you are crating 10 threads there exist 10 different this references.
That is one of the reasons it is preferred to not extend Thread class, but to implement Runnable interface and pass instance of this interface to as many threads as you want.
Another problem is that you are printing edited value without waiting for threads to finish.
What you need is creating one instance which will hold value you want to change and invoke synchronized method from only one instance, because as mentioned by default synchronized void method is synchronized on this (current object on which this method is invoked).
class MyTask implements Runnable {
public volatile int counter;
MyTask(int n) {
counter = n;
}
public void run() {
System.out.println(Thread.currentThread().getName()+" entered run");
go();
System.out.println(Thread.currentThread().getName()+" finished run");
}
synchronized void go() {
System.out.println(Thread.currentThread().getName()+" entered go");
for (int i = 0; i < 10000; i++) {
counter++;
}
System.out.println(Thread.currentThread().getName()+" left from go");
}
}
class Luncher {
public static void main(String args[]) throws InterruptedException {
//lets create task we want to execute in parallel
MyTask task = new MyTask(0);
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++)//create thread instances
threads[i] = new Thread(task);
for (int i = 0; i < 10; i++)//start threads
threads[i].start();
for (int i = 0; i < 10; i++)
threads[i].join();//hold main thread to wait till all threads will finish
System.out.println(task.counter);
}
}
with
c[i] = new C(0);
you are creating new instance of c every time
with
synchronized void go()
{
for (int i = 0; i < 10000; i++)
{
cr++;
}
}
you will always get the number less than 10000 i dont know why you are expecting 100,000
Is it a typo mistake i < 10000 where you should have u used 100,000 ?
To answer your last question
I made method go() synchronized, so it should be used by only one thread at a time..?
if only one thread at a time, you don't need synchronized(multithreading concept).
It doesn't give me 100,000, but rather numbers below 100k. Why?
Every thing is working fine but main thread is not waiting for other threads to complete the calculation hence output is random in main thread.
Use Thread#join() so that main thread waits for all the other threads to die before executing the last line of the main thread.
for (int i = 0; i < 10; i++) {
c[i].start();
c[i].join(); // Waits for this thread to die
}
System.out.println(C.cr); // output 100000
It's worth reading How do I pause main() until all other threads have died?