I'm trying to write code in Java to read a file by couple of threads and count the words in them. Each thread should read different lines. It counts words well (when I let 1 thread run) but my threads are reading same line and increments line counter at the same time. I was sure that the synchronized keyword in read method will fix it,but it didn't. What should I do to fix it?
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
public class WordCounterr implements Runnable {
private static Hashtable<String, Integer> ht = new Hashtable<String, Integer>();
private int lineCounter;
private String path;
private int tNumber;
//private final AtomicInteger whichLine = new AtomicInteger();
private static int whichLine;
private static boolean flag;
public WordCounterr(String path,int num){
lineCounter = 0;
//whichLine = 0;
flag= false;
this.path=path;
tNumber = num;
}
public void countWords(String s) throws IOException{
char[] c = s.toCharArray();
String str="";
char ch;
for(int k=0;k<c.length;k++){
ch=c[k];
if((ch>40 && ch<91) ||(ch>96 && ch<123)){
if(ch>40 && ch<91)
ch+=32;
str+=ch;
}
else if(ch==32 ||k==c.length-1){
if(str.length()>1){ //sprawdzamy czy funkcja znalazla juz
if(ht.containsKey(str)) //takie slowo
ht.put(str,ht.get(str)+1); //znalazla - powiekszamy wartosc przy kluczu
else
ht.put(str,1); //nie znalazla - dodajemy slowo do Hashtable
}
str="";
}
}
}
public synchronized void read(String path) throws IOException{
BufferedReader buf=new BufferedReader(new FileReader(path));
String linia ;
for(int i=0;i<whichLine;i++){
linia=buf.readLine();
}
if((linia=buf.readLine())!=null){
System.out.println(linia);
countWords(linia);
lineCounter++;
System.out.println("watek nr:"+tNumber+"ktora linia:"+whichLine);
whichLine++;
/*try{
Thread.sleep(100);
}catch(InterruptedException el){
System.out.println(el.toString());
}*/
} else
setFlag(true);
buf.close(); //pamietamy o zamknieciu pliku
}
public synchronized void print(){
if(getFlag()){
setFlag(false);
System.out.println(ht);
}
System.out.println("watek nr: "+tNumber+", przeanalizowano "+ lineCounter+ "linii tekstu");
}
public void setFlag(boolean val){
flag=val;
}
public boolean getFlag(){
return flag;
}
#Override
public void run() {
try{
while(getFlag()==false) {
read(path);
Thread.yield(); //let other thread read
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}catch(IOException ex){
System.out.println(ex.toString());
}//catch(InterruptedException el){
// System.out.println(el.toString());
//}
print();
}
public static void main(String[] args) throws IOException, InterruptedException{
String path = args[0];
int tNum = Integer.parseInt(args[1]);
Thread[] thread = new Thread[tNum]; // tablica w?tków
for (int i = 0; i < tNum; i++){
thread[i] =new Thread(new WordCounterr(path,i));
}
for (int i = 0; i < tNum; i++)
thread[i].start();
}
}
The synchronized modifier is defined so: it is not possible for two invocations of synchronized methods on the same object to interleave.
You are calling the method read in each of your Threads.
However you are not calling the same read method because you are passing new instances of WordCounterr to each new Thread. This means you are calling the method on different objects which will not be effected by the synchronized modifier.
To fix this try:
WordCounterr reader = new WordCounterr(path,0); //I changed i to 0 because it can't differentiate between threads with a simple int. This is because each Thread now references the same object.
Thread[] thread = new Thread[tNum]; // tablica w?tków
for (int i = 0; i < tNum; i++){
thread[i] =new Thread(reader);
}
Rather than:
Thread[] thread = new Thread[tNum]; // tablica w?tków
for (int i = 0; i < tNum; i++){
thread[i] =new Thread(new WordCounterr(path,i));
}
I hope this helps :)
I am guessing that it still will be inefficiently reading file content.
Try change the synchronization point. It should be to placed in read method. This method reads whole file content. Rather that try synchronized just reading next line of this file. You can achieve it by putting to each WordCounterr instance the same reader file instance and synchronized only process of moving pointer to next line read content of this line. Counting words in the line can be done without synchronization and only updating HashTable should be synchronized.
Reading file content in parallel can be synchronized as below:
static class Reader implements Runnable {
int lineReaded = 0;
final Scanner scanner;
Reader(Scanner scanner) {
this.scanner = scanner;
}
public void run() {
boolean hasNext = true;
while (hasNext) {
hasNext = false;
synchronized (scanner) {
if (scanner.hasNext()) {
hasNext = true;
String line = scanner.nextLine();
++lineReaded;
}
}
try {
Thread.sleep((long) (Math.random() * 100));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Related
I am reading two text files concurrently line by line.
What I am specifically want to do is when the lineCount on each thread are the same I want to take a look at the string that the scanner is currently reading.
I looked around for certain pattern I can implement like Compare and Swap and Slipped Condition but I cannot wrap my head around how it would help me achieve my goal. I am new to concurrency programming.
What I have managed so far is to synchronize the string reading and printing with counterSync method and I know that I have carry out my thread lock/pause operation there and take a look at the string.
public class concurrencyTest {
public static void main(String[] args) throws IOException {
String filePath1 = "path1.txt";
String filePath2 = "path2.txt";
reader reader = new reader();
MyThread source = new MyThread(reader, filePath1);
MyThread target = new MyThread(reader, filePath2);
source.start();
target.start();
}
static public class reader {
void read(String filePath) throws IOException {
readFile(filePath);
}
}
static synchronized void counterSync(String thread) {
System.out.println(thread);
}
static class MyThread extends Thread {
reader reader;
String filePath;
MyThread(reader reader, String filePath) {
this.reader = reader;
this.filePath = filePath;
}
#Override
public void run() {
try {
reader.read(filePath);
} catch (IOException e) {
e.printStackTrace();
}
}
}
static void readFile(String filePath) throws IOException {
FileInputStream inputStream = null;
Scanner sc = null;
int lineCount = 0;
try {
inputStream = new FileInputStream(filePath);
sc = new Scanner(inputStream, "UTF-8");
while (sc.hasNextLine()) {
lineCount++;
System.out.println(lineCount + "===" + sc.nextLine());
counterSync(sc.nextLine());
}
if (sc.ioException() != null) {
throw sc.ioException();
}
} finally {
if (inputStream != null) {
inputStream.close();
}
if (sc != null) {
sc.close();
}
}
}
}
Ok, what you are looking for is a little bit complex but still possible.
Your question lacks of some examples so correct me if I'm wrong in something.
You have 2 threads:
thread1
thread2
and 2 files:
file1
file2
Content of file1:
file1
file2
file3
file4
file5
file6
file7
file8
file9
Content of file2:
file11
file22
file33
file44
file55
file66
file77
file88
file99
You want to stop all threads on the same line numbers and do some oeration with the output.
This is the thread implementation for reading the files, we will instantiate 2 instance of it, each instance will manage a file.
static class ReaderThread extends Thread {
private File fileToRead;
public final Object lock = new Object();
private String currentLine;
private AtomicInteger lineCount = new AtomicInteger(0);
public ReaderThread(File fileToRead) {
this.fileToRead = fileToRead;
}
#Override
public void run() {
synchronized (lock) {
try {
Stream<String> lines = Files.lines(Path.of(fileToRead.getPath()));
lines.forEach(line -> {
currentLine = line;
// Here's your logic on different lines
if (lineCount.get() == 4 || lineCount.get() == 5 || lineCount.get() == 6) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lineCount.getAndIncrement();
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
public String getCurrentLine() {
return currentLine;
}
public boolean isLocked() {
return getState().equals(State.WAITING);
}
}
Then we will use an helper thread to notify the reader threads when our elboration will be ok:
static class HelperThread extends Thread {
private List<ReaderThread> threads;
#Override
public void run() {
while (true) {
if (threads.stream().allMatch(ReaderThread::isLocked)) {
System.out.println("next line:");
threads.forEach(thread -> {
synchronized (thread.lock) {
System.out.println(thread.getCurrentLine());
thread.lock.notify();
}
});
System.out.println("\n");
}
}
}
public HelperThread(List<ReaderThread> threads) {
this.threads = threads;
}
}
Finally the main class for testing all:
public static void main(String[] args) {
File f1 = new File(Objects.requireNonNull(Main.class.getClassLoader().getResource("file1.txt")).getFile());
File f2 = new File(Objects.requireNonNull(Main.class.getClassLoader().getResource("file2.txt")).getFile());
ReaderThread t1 = new ReaderThread(f1);
ReaderThread t2 = new ReaderThread(f2);
HelperThread helperThread = new HelperThread(List.of(t1, t2));
helperThread.start();
t1.start();
t2.start();
}
Executing the program will result in this output:
next line:
file5
file55
next line:
file6
file66
next line:
file7
file77
Here's the complete list of imports:
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
Please note: this is a rude example, you need to manage with the correct shutdown of the threads, some modifiers are public so encapsulate it following the java guidelines, coorrectly manage all exceptions and do some general refactor.
If you want a more versatile implementation, to interpolate different lines, the following should be ok:
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
public class Main2 {
public static void main(String[] args) {
File f1 = new File(Objects.requireNonNull(Main2.class.getClassLoader().getResource("file1.txt")).getFile());
File f2 = new File(Objects.requireNonNull(Main2.class.getClassLoader().getResource("file2.txt")).getFile());
ReaderThread t1 = new ReaderThread(f1);
ReaderThread t2 = new ReaderThread(f2);
HelperThread helperThread = new HelperThread(List.of(t1, t2));
helperThread.start();
t1.setName("Reader1");
t1.setName("Reader2");
t1.start();
t2.start();
}
static class ReaderThread extends Thread {
private final File fileToRead;
private final Object lock = new Object();
private final AtomicInteger lineCount = new AtomicInteger(0);
private String currentLine;
public ReaderThread(File fileToRead) {
this.fileToRead = fileToRead;
}
#Override
public void run() {
synchronized (lock) {
try {
Stream<String> lines = Files.lines(Path.of(fileToRead.getPath()));
lines.forEach(line -> {
currentLine = line;
lineCount.getAndIncrement();
});
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void lock() throws InterruptedException {
this.lock.wait();
}
public void unlock() {
this.lock.notify();
}
public boolean isLocked() {
return getState().equals(State.WAITING);
}
public Object getLock() {
return lock;
}
public AtomicInteger getLineCount() {
return lineCount;
}
public String getCurrentLine() {
return currentLine;
}
}
static class HelperThread extends Thread {
private List<ReaderThread> threads;
#Override
public void run() {
while (true) {
threads.forEach(t -> {
try {
if (t.getName().equals("Reader1") && t.getLineCount().get() == 3) t.lock();
if (t.getName().equals("Reader2") && t.getLineCount().get() == 4) t.lock();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
if (threads.stream().allMatch(ReaderThread::isLocked)) {
System.out.println("next line:");
threads.forEach(t -> {
synchronized (t.getLock()) {
System.out.println(t.getCurrentLine());
t.unlock();
}
});
System.out.println("\n");
}
}
}
public HelperThread(List<ReaderThread> threads) {
this.threads = threads;
}
}
}
Be sure that the HelperThread starts before the other threads or it's possible to loose some data.
It seems that you didn't post a complete example. But, a few general comments:
You might be able to get away with using "compare-and-swap" logic for an integer, but you should not expect it to work for a more-sophisticated thing like a Java "String" or any sort of container.
You should simply use the synchronization-objects provided in the language. If you are going to update or even to examine a shared data structure, you must be holding the proper lock.
Of course, "thread-safe queues" are very helpful in many designs because they facilitate the most-common activity – message-passing – and allow the various threads to operate graciously at slightly-varying speeds. You still have to lock anything that's shared, but nonetheless it's a useful design that's really as old as the Unix® "pipe."
You can use
java.util.concurrent.CyclicBarrier
A synchronization aid that allows a set of threads to all wait for
each other to reach a common barrier point. CyclicBarriers are useful
in programs involving a fixed sized party of threads that must
occasionally wait for each other. The barrier is called cyclic because
it can be re-used after the waiting threads are released.
A CyclicBarrier supports an optional Runnable command that is run once
per barrier point, after the last thread in the party arrives, but
before any threads are released. This barrier action is useful for
updating shared-state before any of the parties continue.
Here is an example using this class:
public static void main(String[] args) throws IOException {
String filePath1 = "path1.txt";
String filePath2 = "path2.txt";
ReaderThread reader1 = new ReaderThread(filePath1);
ReaderThread reader2 = new ReaderThread(filePath2);
CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> {
//processing when condition met in both thread
List<String> lines1 = reader1.getLines();
List<String> lines2 = reader2.getLines();
System.out.println(lines1.get(lines1.size() - 1) + " " + lines2.get(lines2.size()-1));
});
reader1.setCyclicBarrier(cyclicBarrier);
reader2.setCyclicBarrier(cyclicBarrier);
reader1.start();
reader2.start();
}
public static class ReaderThread extends Thread {
CyclicBarrier cyclicBarrier;
String file;
List<String> lines = new ArrayList<>();
public void setCyclicBarrier(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
public ReaderThread(String file) {
this.file = file;
}
#Override
public void run() {
try (BufferedReader reader = Files.newBufferedReader(Paths.get(file))) {
String line = null;
for (int i = 0; (line = reader.readLine()) != null; i++) {
lines.add(line);
//condition do something
if (i % 10 == 0) {
cyclicBarrier.await();
}
}
} catch (IOException | InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
}
public List<String> getLines() {
return new ArrayList<>(lines);
}
}
And output:
this is from file1 1232123321312 this is from file 2 1232123321312
this is from file1 1232123321312 this is from file 2 1232123321312
this is from file1 1232123321312 this is from file 2 1232123321312
So i need to process a couple data files using threads (already splitted), and i'm having issues on how to stop the main thread till all the subthreads finish.
i looked around and tried to use join() but this causes an issue:
If i join the main thread with the last thread then since the other threads run at the same time, the last thread is not always the last one to finish
If i join the main thread with all the other threads then they don't run at the same time, the second needs the first to finish first.
also tried wait() and notify() but had even more issues. here's a part of my code
public class Matrix extends MapReduce {
ArrayList<String> VecteurLines = new ArrayList<String>();
protected int[] nbrLnCol = {0,0};
protected static double[] res;
public Matrix(String n) {
super(n);
}
public Matrix(String n,String m){
super(n,m);
}
public void Reduce() throws IOException, InterruptedException, MatrixException {
for (int i = 1; i <= Chunks; i++) {
Thread t=new Thread(new RunThread(VecteurLines,i,this));
t.start();
}
}
And here's the class that handles the threads
public class RunThread extends Matrix implements Runnable {
Matrix ma;
ArrayList<String> vec;
int threadNbr;
public RunThread(ArrayList<String> vec, int threadNbr,Matrix ma) {
super("","");
this.vec=vec;this.threadNbr=threadNbr;this.ma=ma; }
#Override
public void run() {
FileInputStream fin = null;
try {
fin = new FileInputStream(ma.getNom()+threadNbr+".txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Scanner sc = new Scanner(fin);
while (sc.hasNext()) {
String nextString = sc.next();
ma.nbrLnCol[0]++;
String [] arr = nextString.split(",");
ma.nbrLnCol[1]=arr.length;
double c=0;
for(int j=0;j<arr.length;j++)
{
c+=(Double.parseDouble(arr[j])*Double.parseDouble(vec.get(j)));
}
res[threadNbr-1]=c;
}
sc.close();
try {
fin.close();
} catch (IOException e) {
e.printStackTrace();
}
File file = new File(ma.getNom()+threadNbr+".txt");
file.delete();
}
Try like this:
private List<Thread> threadList = new ArrayList<>();
public void Reduce() {
threadList.clear();
for (int i = 1; i <= Chunks; i++) {
Thread t =new Thread(new RunThread(VecteurLines,i,this));
threadList.add(t);
}
// start all worker threads
for(int i=0; i<threadList.size(); i++){
threadList.get(i).start();
}
// wait until all worker threads is finished
while (true) {
int threadIsNotLive = 0;
for (int i = 0; i < threadList.size(); i++) {
Thread t = threadList.get(i);
if (!t.isAlive() || t == null) {
++threadIsNotLive;
}
}
if(threadIsNotLive>0 && (threadList.size() == threadIsNotLive)){
break;
// all worker threads is finished
}
else {
Thread.sleep(50);
// wait until all worker threads is finished
}
}
}
OR
public void Reduce() {
List<Thread> threadList = new ArrayList<>();
for (int i = 1; i <= Chunks; i++) {
Thread t =new Thread(new RunThread(VecteurLines,i,this));
threadList.add(t);
}
// start all worker threads
for(int i=0; i<threadList.size(); i++){
threadList.get(i).start();
threadList.get(i).join();
}
}
I believe you need two points in your code:
Your main thread has to end last after all the thread's executed because you said
"how to stop the main thread till all the subthreads finish"
.
Second ,the thread should finish one after another that is the 2nd thread should finish after 1st thread as you said
"the second needs the first to finish first."
Here is my code to do it with join .
public class Matrix extends MapReduce {
ArrayList<String> VecteurLines = new ArrayList<String>();
protected int[] nbrLnCol = {0,0};
protected static double[] res;
public Matrix(String n) {
super(n);
}
public Matrix(String n,String m){
super(n,m);
}
public void Reduce() throws IOException, InterruptedException, MatrixException {
Thread t = null;
for (int i = 1; i <= Chunks; i++) {
Thread t=new Thread(new RunThread(t,VecteurLines,i,this));
t.start();
}
t.join(); // finally main thread joining with the last thread.
}
and
public class RunThread extends Matrix implements Runnable {
Matrix ma;
ArrayList<String> vec;
int threadNbr;
Thread t;
public RunThread(t,ArrayList<String> vec, int threadNbr,Matrix ma) {
this.t = t;
super("","");
this.vec=vec;this.threadNbr=threadNbr;this.ma=ma; }
#Override
public void run() {
FileInputStream fin = null;
try {
fin = new FileInputStream(ma.getNom()+threadNbr+".txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Scanner sc = new Scanner(fin);
while (sc.hasNext()) {
String nextString = sc.next();
ma.nbrLnCol[0]++;
String [] arr = nextString.split(",");
ma.nbrLnCol[1]=arr.length;
double c=0;
for(int j=0;j<arr.length;j++)
{
c+=(Double.parseDouble(arr[j])*Double.parseDouble(vec.get(j)));
}
res[threadNbr-1]=c;
}
sc.close();
try {
fin.close();
} catch (IOException e) {
e.printStackTrace();
}
File file = new File(ma.getNom()+threadNbr+".txt");
file.delete();
if(t!=null){
t.join(); //join with the previous thread eg. thread2 joining with thread1
}
}
Right now I write a Java program that has as purpose detect deadlocks and recovery from this situation. The program input is two numbers, N = Number of types of resources and M = Number of process.
I wanted to do something like this:
private static void test2() {
final ReentrantLock lock1 = new ReentrantLock();
final ReentrantLock lock2 = new ReentrantLock();
Thread thread1 = new Thread(new Runnable() {
#Override public void run() {
try {
lock1.lock();
System.out.println("Thread1 acquired lock1");
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException ignore) {}
lock2.lock();
System.out.println("Thread1 acquired lock2");
}
finally {
lock2.unlock();
lock1.unlock();
}
}
});
thread1.start();
Thread thread2 = new Thread(new Runnable() {
#Override public void run() {
try {
lock2.lock();
System.out.println("Thread2 acquired lock2");
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException ignore) {}
lock1.lock();
System.out.println("Thread2 acquired lock1");
}
finally {
lock1.unlock();
lock2.unlock();
}
}
});
thread2.start();
// Wait a little for threads to deadlock.
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException ignore) {}
detectDeadlock();
}
But instead of 2, N locks and I have several problems for doing this. Here my code with my attempt:
class Main {
private static int MAX_AVAILABLE = 10;
private static int IDLE = 1000;
public static void main(String[] args) throws java.lang.Exception{
int n, m; //number of resources and process, respectively
ReentrantLock[] resources; // Locks for resources
int[] available; // Number of instances per resource
Process[] processes; // Processes array
DeadlockDetector supervisor; // Deadlock detaction class
n = Integer.valueOf(args[0]);
m = Integer.valueOf(args[1]);
resources = new ReentrantLock[n];
available = new int[n];
processes = new Process[m];
supervisor = new DeadlockDetector();
// Create resources array
for(int i=0; i<n; ++i){
available[i] = (int)(Math.floor(Math.random()*MAX_AVAILABLE + 1));
resources[i] = new ReentrantLock();
System.out.println("R"+String.valueOf(i+1)+"-> instances: "+String.valueOf(available[i]));
}
// Creating processes
for(int i=0; i<m; ++i){
processes[i] = new Process(i, resources, available, n);
System.out.println("P"+String.valueOf(i+1)+"-> requested "+Arrays.toString(processes[i].requested));
processes[i].start();
}
//Run deadlock detection
try {
TimeUnit.MILLISECONDS.sleep(IDLE);
}catch (InterruptedException ignore){}
supervisor.start();
}
}
class Process extends Thread{
public int id;
public int total; // Total of resources instances needed for finished the process
public ReentrantLock[] resources;
public int[] requested; // Number of instances needed per resource type
public boolean[] needed; // Boolean indicating whether the process needs at least one instance of the resource i
public int n;
private static int MIN_TIME = 1000;
private static int MAX_TIME = 3000;
public Process(int index, ReentrantLock[] res, int[] available, int n_resources){
id = index;
n = n_resources;
resources = res;
total = 0;
requested = new int[n];
needed = new boolean[n];
for(int i=0; i<n; ++i){
requested[i] = (int)(Math.floor(Math.random()*available[i]));
needed[i] = requested[i] > 0;
total += requested[i];
}
}
#Override
public void run(){
int resourceT = 0;
int timeToSleep;
System.out.println("P"+String.valueOf(id+1)+" begin running");
try{
while(total > 0){
resourceT = (int)(Math.floor(Math.random()*n));
if(requested[resourceT] < 1){
System.out.println("P"+String.valueOf(id+1)+"-> I do not need more R"+String.valueOf(resourceT+1));
continue;
}
System.out.println("P"+String.valueOf(id+1)+"-> I'll take R"+String.valueOf(resourceT+1));
resources[resourceT].lock();
timeToSleep = (int)(Math.floor(Math.random()*(MAX_TIME - MIN_TIME)) + MIN_TIME);
try{
TimeUnit.MILLISECONDS.sleep(timeToSleep);
}catch (InterruptedException ignore){}
--total;
--requested[resourceT];
}
}finally{
for(int i=0; i<n; ++i){
if(needed[i] && resources[i].isHeldByCurrentThread())
resources[i].unlock();
}
}
System.out.println("P"+String.valueOf(id+1)+"-> Im finished");
}
}
class DeadlockDetector extends Thread{
public ThreadMXBean threadBean;
public long[] threadIds;
public DeadlockDetector(){
}
#Override
public void run(){
Boolean good;
this.threadBean = ManagementFactory.getThreadMXBean();
threadIds = threadBean.findDeadlockedThreads();
int deadlockedThreads = threadIds != null? threadIds.length : 0;
if(deadlockedThreads>1){
good = false;
System.out.println("Number of deadlocked threads: " + deadlockedThreads);
//recoverDeadlock();
//break;
}
}
public void recoverDeadlock(){
}
}
Please, could anyone help me fix this detail? Thanks!
import java.awt.List;
import java.util.ArrayList;
import java.util.Random;enter code here
public class shared {
private int [] buffer;
private int capacity;
Object lock;//=new Object();
int count=0;
int i,j;
//int i=0,j=0;
public shared(int capacity){
this.capacity = capacity;
buffer = new int[capacity];
i=0;
j=0;
lock = new Object();
//for(int k=0;k<capacity;k++){
//buffer[k]=0;
//}
}
public void producer() throws InterruptedException {
//synchronized(lock){
while(true){
synchronized(lock){
Random rn = new Random();
int number = rn.nextInt(100);
Thread.sleep(1000);
while(count==capacity){
try{
System.out.println("BUffer is full");
lock.wait();
}catch(InterruptedException e){
}
//System.out.println("buffer is full");
}
System.out.println("producing" + number);
buffer[i] = number;
i = (i+1)%capacity;
count++;
lock.notifyAll();
}
}
}
public void consumer(){
//synchronized(lock){
while(true){
synchronized(lock){
while(count==0){
try{
lock.wait();
}catch(InterruptedException e){
}
}
//int a = buffer.get(0);
//buffer.remove(0);
int consumed = buffer[j];
System.out.println("consuming" + consumed);
j=(j+1)%capacity;
count--;
lock.notifyAll();
if((consumed%2)==0){
System.out.println("the number displayed by the consumer is " + consumed);
}
}
}
}
}
public class producer implements Runnable {
shared h;
public producer(shared s) {
// TODO Auto-generated constructor stub
h=s;
}
public void run(){
//for(int i=0;i<10;i++){
try {
h.producer();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class consumer implements Runnable {
shared h;
public consumer(shared s) {
// TODO Auto-generated constructor stub
h=s;
}
public void run(){
//for(int i=0;i<5;i++){
h.consumer();
}
}
public class implement {
public static void main(String [] args) throws InterruptedException{
shared s = new shared(10);
Thread pro1 = new Thread(new producer(s));
Thread con1 = new Thread(new consumer(s));
pro1.start();
con1.start();
pro1.join();
con1.join();
}
}
This is the entire code that I have written. The problem that I am getting is that my buffer is getting entirely full first then it is getting consumed. I want it to be consumed randomly i.e. when the first element fills up it might get get consumed or after 3-4 elements filled up.
I've reproduced your experiment and checked that, in fact, the producer thread fills the buffer before the consumer comes in. And that's because only when the buffer is full, the producer calls wait to give the consumers a chance.
The behaviour in a multi-threaded environment is always something random. Surely when the execution exits from the producer's synchronized block, the next iteration comes so quickly that it enters again in the block before other threads have a chance to.
If you want to produce and consume with an random ratio, I suggest you other means:
First, move the sleep out of the synchronized block.
Or else, do always a wait first-notify last into your producer loop, but performing a random number of inserts between them.
I have a multithreading program, which sorts threads in order strs times. Every thread has its own monitor. One monitor of this thread (lock) and another monitor of the following thread (unlock) are passed to the constructor of each thread. First, when each thread starts, it must stop when array[0] != this, but if in I write this in line 13, the deadlock appears. So I use Threads.count, which is incremented every iterations. This way the program works. Could you tell me why this happens?
class Foo extends Thread
{
private Object lock, unlock;
Foo(Object lock, Object unlock)
{
this.lock = lock;
this.unlock = unlock;
}
public void run()
{
synchronized(lock)
{
if(Threads.array[Threads.count] != this) // line 13!!!
{
waiter();
}
for(int i = 0; i < Threads.strs; ++i)
{
if(Threads.array[0] == this)
{
System.out.println(i+1);
}
System.out.print(getName() + ' ');
++Threads.count;
if(Threads.array[Threads.thrs-1] == this)
{
System.out.println();
}
if(unlock != lock)
{
synchronized(unlock)
{
unlock.notify();
}
waiter();
}
}
}
}
void waiter()
{
try
{
lock.wait();
}
catch(InterruptedException e)
{
e.printStackTrace();
System.exit(1);
}
}
}
public class Threads
{
public static Thread array[];
public static Object lock[];
public static int count, strs, thrs;
public static void main(String args[])
{
thrs = 0;
strs = 0;
count = 0;
try
{
assert(args.length == 2);
thrs = Integer.parseInt(args[0]);
strs = Integer.parseInt(args[1]);
assert((thrs > 0) && (strs > 0));
}
catch(NumberFormatException | AssertionError e)
{
System.out.println("Uncorrect enter!");
System.exit(1);
}
lock = new Object[thrs];
array = new Thread[thrs];
for(int i = 0; i < thrs; ++i)
{
lock[i] = new Object();
}
for(int i = 0; i < thrs; ++i)
{
if(i != thrs-1)
{
array[i] = new Foo(lock[i],lock[i+1]);
}else
{
array[i] = new Foo(lock[i],lock[0]);
}
array[i].start();
}
}
}
Line 13 basically says "wait to get notified by a preceding thread, unless I am the first thread". Which makes sense: from what I can tell from the code, you want the threads to do their tasks one by one in the order that you have created the threads (which kind of defeats the purpose of using threads, but that is another story).
Also note that the program will not exit since all threads call waiter() at the end the loop.
So the solution is kind of straightforward: have all threads wait at the beginning of the loop, but after creating all threads, trigger the first thread to start running (which in turn will trigger the other threads to start running). Below a slightly adjusted copy of your code with the two changes I mentioned:
class ThreadsInSequence extends Thread
{
private Object lock, unlock;
ThreadsInSequence(Object lock, Object unlock)
{
this.lock = lock;
this.unlock = unlock;
}
public void run()
{
synchronized(lock)
{
for(int i = 0; i < strs; ++i)
{
waiter();
if(array[0] == this)
{
System.out.println(i+1);
}
System.out.print(getName() + ' ');
++count;
if(array[thrs-1] == this)
{
System.out.println();
}
if(unlock != lock)
{
synchronized(unlock)
{
unlock.notify();
}
}
}
}
}
void waiter()
{
try
{
lock.wait();
}
catch(InterruptedException e)
{
e.printStackTrace();
System.exit(1);
}
}
public static Thread array[];
public static Object locks[];
public static int count, strs, thrs;
public static void main(String args[])
{
thrs = 3;
strs = 6;
count = 0;
locks = new Object[thrs];
array = new Thread[thrs];
for(int i = 0; i < thrs; ++i)
{
locks[i] = new Object();
}
for(int i = 0; i < thrs; ++i)
{
if(i != thrs-1)
{
array[i] = new ThreadsInSequence(locks[i],locks[i+1]);
}else
{
array[i] = new ThreadsInSequence(locks[i],locks[0]);
}
array[i].start();
}
synchronized(locks[0]) {
locks[0].notify();
}
}
}