I was looking at a producer-consumer example with wait and notify, even though it works some times it gives exception. Not able to figure out where the problem is.
Exception in thread "Thread-5" java.util.NoSuchElementException at
java.util.LinkedList.removeFirst(Unknown Source) at com.bhatsac.workshop.producerconsumer.ProdNConsumer.consumer(ProdNConsumer.java:55)
at com.bhatsac.workshop.producerconsumer.ProdConsumerInvoker.lambda$5 (ProdConsumerInvoker.java:35)
at java.lang.Thread.run(Unknown Source)
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
public class ProdNConsumer {
LinkedList<Integer> list = new LinkedList<Integer>();
private int LIMIT = 1;
private volatile boolean shutdown = false;
private AtomicInteger counter=new AtomicInteger(0);
private Object lock=new Object();
public void produce() {
while (true) {
synchronized(lock){
System.out.println("In producer :)"+ list.size());
if(this.list.size()==this.LIMIT){
try {
System.out.println("In waiting state producer");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Produced by thread= "+ Thread.currentThread().getName());
list.add(counter.getAndIncrement());
System.out.println("Going to sleep for a while");
lock.notifyAll();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void consumer() {
while (true) {
synchronized(lock){
System.out.println("In consumer :)");
if(list.size()==0){
try {
System.out.println("In waiting state consumer");
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("consumed by thread="+ Thread.currentThread().getName());
list.removeFirst();
lock.notifyAll();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public class ProdConsumerInvoker {
public static void main(String[] args) {
ProdNConsumer pc= new ProdNConsumer();
Thread tc1=new Thread(()->{pc.consumer();});
new Thread(()->{pc.produce();}).start();
new Thread(()->{pc.produce();}).start();
Thread tp1=new Thread(()->{pc.produce();});
new Thread(()->{pc.consumer();}).start();
new Thread(()->{pc.consumer();}).start();
tp1.start();
tc1.start();
}
}
Your producer and consumer threads are using the same lock. When a consumer wakes up and consumes an element, it calls lock.notifyAll(), which will wake up all consumers and producers waiting on it. Another consumer wakes up thinking there are items in the list, but it removes the first item from an empty list, causing the exception.
In the consumer, instead of if(list.size()==0), use while(list.size()==0). Similar reasoning applies to the producer as well. Just because the thread woke up doesn't mean that the condition it is waiting on is true. It only means that before the thread woke up the condition was true. It must check it again.
Related
I created two separate threads one for writing into a list and second for removing from the list.
package com.produ.consu;
public class Test {
public static void main(String[] args) {
Operations operations = new Operations();
Runnable r1 = new ThreadsClass(operations);
Runnable r2 = new ThreadsClass(operations);
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.setName("READ");
t2.setName("WRITE");
t1.start();
t2.start();
}
}
Above is Test class where I created threads.
package com.produ.consu;
public class ThreadsClass implements Runnable {
Operations operations;
ThreadsClass(Operations operations){
this.operations=operations;
}
#Override
public void run() {
// TODO Auto-generated method stub
if(Thread.currentThread().getName().equals("WRITE")) {
operations.writeList();
}
else {
operations.readList();
}
}
}
Above is class calling synchronized methods based on the thread name:
import java.util.ArrayList;
import java.util.List;
public class Operations {
List<Integer> list=null;
int count=0;
boolean flag;
Operations(){
list=new ArrayList<>();
flag=true;
}
public synchronized void writeList() {
// TODO Auto-generated method stub
while(true) {
if(flag) {
count++;
list.add(count);
System.out.println("inise if block...."+Thread.currentThread().getName());
System.out.println(list);
flag=false;
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else {
notify();
}
}
}
public synchronized void readList() {
// TODO Auto-generated method stub
while(true) {
if(!flag) {
Integer i = list.remove(0);
System.out.println(i+"..removed at index by"+Thread.currentThread().getName());
flag=true;
notify();
}
else {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
Above is where I mentioned functionality.
So write thread hast to write element to list and wait until it is removed by the second thread.
Once removed second should notify 1st and wait for until element inserted.
But getting...
inise if block....WRITE [1]
Not even removed and it has to be a continuous process.
Give me suggestions on given code.
You should wait() inside the else block also, otherwise the while will continue to run if the if is not satisfied and the other thread won't get a chance to execute.
After the read/write operation is performed the thread should call notify to wake up the other thread and itself should go in the waiting state.
public synchronized void writeList() {
while (true) {
if (flag) {
count++;
list.add(count);
System.out.println("inise if block...." + Thread.currentThread().getName());
System.out.println(list);
flag = false;
try {
notify(); //notify the read thread that write is complete
wait(); // go into the waiting state so that no further write is done until the current element is removed by the read thread.
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
try {
wait(); //wait in else, otherwise while will run endlessly
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public synchronized void readList() {
while (true) {
System.out.println("in read");
if (!flag) {
Integer i = list.remove(0);
System.out.println(i + "..removed at index by" + Thread.currentThread().getName());
flag = true;
try {
notify(); //notify write thread that read is complete
wait(); //go into wait until new element is inserted
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
try {
wait(); //wait in else otherwise while runs endlessly
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
You should replace the method synchronization with more granular synchronization: wrap the operations that access the list and update count with a synchronized block.
Alternatively, use a linked blocking queue to pass “messages” between threads (or, in more advanced scenarios, a messaging solution such as Akka, Kafka, zeromq, or other similar solutions)
Since you only add one elemet at a time you could also use a Exchanger.
Take a look at the Java concurrent package.
import java.io.IOException;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Foo {
public static void main(String[] args) throws IOException, InterruptedException {
final Exchanger<Integer> exchanger = new Exchanger<>();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> {
// producer
int count = 0;
while (!Thread.currentThread().isInterrupted()) {
try {
exchanger.exchange(count++);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
executorService.execute(() -> {
// reader
while (!Thread.currentThread().isInterrupted()) {
try {
System.out.println("consume " + exchanger.exchange(null));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
System.in.read();
executorService.shutdownNow();
executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("Shut down");
}
}
Below is the consumer producer problem code, but the code is not working as expected. Here the consumer and producer are supposed to be just producing and consuming one object.
public class ProducerConsumer {
private static LinkedList<Integer> linkedList = new LinkedList<>();
public static void main(String a[]) throws InterruptedException {
Thread producer = new Thread(new Runnable() {
#Override
public void run() {
synchronized(this) {
while (linkedList.size() == 1) {
try {
wait();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Produced");
linkedList.add(1);
notify();
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread consume = new Thread(new Runnable() {
#Override
public void run() {
// produce
synchronized(this) {
while (linkedList.isEmpty()) {
try {
wait();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Consumed");
linkedList.removeFirst();
notify();
try {
Thread.sleep(1000);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
});
producer.start();
consume.start();
producer.join();
consume.join();
}
}
We get the output as : Produced
And the program hangs.
Please help with possible solutions/ explanations
Use a shared lock. In the posted code each Runnable is using itself as a lock so no actual locking takes place.
When a thread waits, another thread needs to call notify on the same lock in order to wake up the waiting thread. We know from your logging that the Producer thread does its thing, but since the notify acts on a lock that is not the same as the one the Consumer is using, the consumer thread never wakes up.
Changing the code to use a shared lock works:
import java.util.*;
public class ProducerConsumer { private static LinkedList linkedList = new LinkedList();
public static void main(String a[]) throws InterruptedException {
final Object lock = new Object();
Thread producer = new Thread(new Runnable() {
#Override
public void run() {
synchronized (lock) {
while (linkedList.size() ==1) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Produced");
linkedList.add(1);
lock.notify();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread consume = new Thread(new Runnable() {
#Override
public void run() {
// produce
synchronized (lock) {
while (linkedList.isEmpty()) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Consumed");
linkedList.removeFirst();
lock.notify();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
producer.start();
consume.start();
producer.join();
consume.join();
}
}
Output for this is:
c:\example>java ProducerConsumer
Produced
Consumed
which I think is what you're expecting.
Btw see this other answer I wrote for a dirt-simple implementation of a queue; you are better off protecting the shared data structure than putting the code in the threads accessing the data structure, especially look at how much easier the code is to write.
Concurrency means that you can not know before runtime which Thread will end first. So you can not know which of the Consumer and Producer is launched, executed or finished first.
To help you, you can use a cyclic barrier https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html or applying the Fork/Join Framework https://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html
Your synchronized blocs just say : only one Thread at a time can execute this part of code, not execute the first and the second after.
An example of how CyclicBarrier works :
service = Executors.newFixedThreadPool(numThreadsTotal);
CyclicBarrier c = new CyclicBarrier(numThreadsToWait);
runProducer();
c.await();
runConsumer();
It will wait until the there is as much Threads as numThreadsToWait that have execute the runProducer to execute the runConsumer().
Perhaps using a Thread Pool with a size of 1 could help you, but you will loose the benefits of concurrency.
I think best what you can do, is use BlockingQueue.
I have an issue with the following piece of code for CyclicBarrier.
MyJavaCyclicBarrierExample.java:::::::
import java.util.Date;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class MyJavaCyclicBarrierExample {
public static void main(String[] args) {
//3 threads are part of the barrier, ServiceOne, ServiceTwo and this main thread calling them.
final CyclicBarrier barrier = new CyclicBarrier(2);
Thread serviceOneThread = new Thread(new ServiceOne(barrier));
Thread serviceTwoThread = new Thread(new ServiceTwo(barrier));
System.out.println("Starting both the services at "+new Date());
serviceOneThread.start();
serviceTwoThread.start();
//Lets say main also has to do some work
try {
System.out.println("Main is going to do some work....");
Thread.sleep(10000);
System.out.println("Main has finished its work....");
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
System.out.println("Main is now going to wait at the barrier....");
barrier.await();
System.out.println("Main woken up at the barrier....");
} catch (InterruptedException e) {
System.out.println("Main Thread interrupted!");
e.printStackTrace();
} catch (BrokenBarrierException e) {
System.out.println("Main Thread interrupted!");
e.printStackTrace();
}
System.out.println("Ending both the services at "+new Date());
}
}
ServiceOne.java :::::::::
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class ServiceOne implements Runnable {
private final CyclicBarrier cyclicBarrier;
public ServiceOne(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
#Override
public void run() {
System.out.println("Starting service One...");
try {
Thread.sleep(3000); //assuming service one does some business logic here...
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("Service One has finished its work... waiting for others...");
try {
System.out.println("ServiceOne is now going to wait at the barrier....");
cyclicBarrier.await(); //Let's wait for the other threads at the cyclic barrier.
System.out.println("ServiceOne woken up at the barrier....");
} catch (InterruptedException e) {
System.out.println("Service one interrupted!");
e.printStackTrace();
} catch (BrokenBarrierException e) {
System.out.println("Service one interrupted!");
e.printStackTrace();
}
System.out.println("The wait is over, lets complete Service Two!");
}
}
ServiceTwo.java:::::::::
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class ServiceTwo implements Runnable {
private final CyclicBarrier cyclicBarrier;
public ServiceTwo(CyclicBarrier cyclicBarrier) {
this.cyclicBarrier = cyclicBarrier;
}
#Override
public void run() {
System.out.println("Starting service Two....");
try {
Thread.sleep(2000); //assuming service one does some business logic here...
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("Service Two has finished its work.. waiting for others...");
try {
System.out.println("ServiceTwo is now going to wait at the barrier....");
cyclicBarrier.await(); //Let's wait for the other threads at the cyclic barrier.
System.out.println("ServiceTwo woken up at the barrier....");
} catch (InterruptedException e) {
System.out.println("Service one interrupted!");
e.printStackTrace();
} catch (BrokenBarrierException e) {
System.out.println("Service one interrupted!");
e.printStackTrace();
}
System.out.println("The wait is over, lets complete Service One!");
}
}
My question is, when I run this code with CyclicBarrier at two levels, it always ends up into a deadlock it seems. Whereas, when I run the code with CyclicBarrier at level 1 or three, i.e. new CyclicBarrier(1) or new CyclicBarrier(3), it always completes successfully. What is the issue with level two then?
CyclicBarrier is cyclic, which means it can be reused. When the barrier is initialized with argument 2, after tripped by serviceOneThread and serviceTwoThread, a new generation starts. The main thread can not trip it alone.
Maybe you need a CountDownLatch.
I am learning threading in java. As per the description of finally block in an Oracle tutorial:
Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.
So I tried to interrupt a thread in try catch block and check whether finally is executed in following class. But as per the output of the program, finally block is executed. Can someone explain what happened?
package com.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestLock{
public static void main(String[] args) throws InterruptedException {
MyThread lockT= new MyThread();
Thread t= new Thread(lockT);
t.setName("TempThread1");
t.start();
Thread.sleep(1000);
t.interrupt();
}
}
class MyThread implements Runnable {
Lock lock;
public MyThread() {
lock= new ReentrantLock();
}
#Override
public void run() {
try {
if(lock.tryLock()){
Thread.sleep(5000);
while (!Thread.currentThread().isInterrupted()) {
System.out.println("My thread name is "+ Thread.currentThread().getName());
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
System.out.println("finally ");
lock.unlock();
}
}
}
The rule here is saying: may not execute which does not mean it will not execute.
So basically the rule is saying: don't rely that the finally block will be executed, we don't provide such guarantees.
I know it's a old thread but I'd like to present a situation where the threads get interrupted and doesn't execute finally: Here is the sample code:
public class Test {
public static void main(String[] args) {
Test test = new Test();
test.LockWork();
}public void LockWork() {
WithLock withLock = new WithLock();
Thread t1 = new Thread(() -> {
withLock.produce();
});
Thread t2 = new Thread(() -> {
withLock.consume();
});
ExecutorService service= Executors.newCachedThreadPool(new WithLockThreadFactory());
Future f1=service.submit(t1);
Future f2=service.submit(t2);
//f1.cancel(true);
try {
System.out.println("-------------------------------------sleeping now-------------------------------------");
Thread.sleep(3000);
System.out.println("-------------------------------------Intereputing Producer-------------------------------------");
f1.cancel(true);
service.shutdown();
Thread.sleep(1000);
System.out.println("is Producer done: "+f1.isDone());
service.awaitTermination(1, TimeUnit.DAYS);
System.out.println("is Consumer done: "+f2.isDone());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Ending Program");
}
now There is my Thread Factory:
public class WithLockThreadFactory implements ThreadFactory {
private int counter;
public WithLockThreadFactory() {
this.counter = 1;
}
#Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "WithLockThreadFactoryThread " + counter);
counter++;
return t;
}
now WithLock Class:
public class WithLock {
ReentrantLock lock = new ReentrantLock(true);
LinkedList<Integer> linkedList = new LinkedList<>();
Condition isEmpty = lock.newCondition();
Condition isFull = lock.newCondition();
int limit = 10;
volatile int interruptCounter = 0;
public void produce() {
System.out.println("WithLock.produce() Name: " + Thread.currentThread().getName());
try {
int value = 1;
while (true) {
lock.lockInterruptibly();
if (limit == linkedList.size()) {
System.out.println("acquiring lock in produce");
isEmpty.await(3000, TimeUnit.MILLISECONDS);
}
linkedList.add(value % limit);
System.out.println("value added to list: " + value % limit);
value++;
isFull.signal();
System.out.println("notifiedy lock in produce");
lock.unlock();
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("I was interupted Producer");
interruptCounter++;
System.out.println("interruptCounter value :" + interruptCounter);
} finally {
lock.unlock();
System.out.println("Finally Unlocked Producuer");
}
System.out.println("Ending things now: Producer");
}
public void consume() {
System.out.println("WithLock.consume() Name: " + Thread.currentThread().getName());
try {
while (true) {
lock.lockInterruptibly();
// no use as poll doesn't throw an exception if the queue is
// empty
if (linkedList.size() == 0) {
System.out.println("acquiring lock in consume");
isFull.await(3000, TimeUnit.MILLISECONDS);
if (interruptCounter > 2) {
break;
}
}
System.out.println("removing element from queue: " + linkedList.poll());
isEmpty.signal();
System.out.println("notifiedy lock in consume");
lock.unlock();
Thread.sleep(1000);
if (interruptCounter != 0) {
interruptCounter++;
}
}
} catch (InterruptedException e) {
System.out.println("I was Interupted Consumer");
} finally {
lock.unlock();
System.out.println("Finally Unlocked Consumer");
}
System.out.println("Ending things now: Consume");
}
}
and this is the output in the console:
-------------------------------------sleeping now-------------------------------------
WithLock.produce() Name: WithLockThreadFactoryThread 1
WithLock.consume() Name: WithLockThreadFactoryThread 2
value added to list: 1
notifiedy lock in produce
removing element from queue: 1
notifiedy lock in consume
acquiring lock in consume
value added to list: 2
notifiedy lock in produce
removing element from queue: 2
notifiedy lock in consume
acquiring lock in consume
value added to list: 3
notifiedy lock in produce
removing element from queue: 3
notifiedy lock in consume
-------------------------------------Intereputing Producer-------------------------------------
I was interupted Producer
interruptCounter value :1
acquiring lock in consume
is Producer done: true
removing element from queue: null
notifiedy lock in consume
acquiring lock in consume
Finally Unlocked Consumer
Ending things now: Consume
is Consumer done: true
Ending Program
This is something I found interesting and wanted to share. I tried it in JAVA8.
If the JVM exits...
Try System.exit() call...
First and foremost, Oracle's tutorials are descriptive and not normative. Your quote should by no means be taken as specification of behavior.
The thread can be interrupted while executing the finally block, in which case the said finally block may indeed fail to complete. This is, however, fully under your control and you can always write such a finally which is not susceptible to this happening.
Rest assured that the finally block will not be skipped over due to a regular InterruptedException occurring within its try block.
If a thread is being repeatedly stop()ped, however, it will be harder to ensure the finally block executes.
class myThreadRun implements Runnable
{
public void run() {
roo();
}
public synchronized void roo()
{
System.out.println("In thread before wait " + Thread.currentThread().getName());
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
JOptionPane.showMessageDialog(null, "After wait in\n"+Thread.currentThread().getName());
System.out.println("In thread after wait " + Thread.currentThread().getName());
//notify();
}
public synchronized void foo()
{
notify();
}
}
public class ThreadingDemo {
public synchronized void Start()
{
System.out.println("Labamba");
myThreadRun mThRun = new myThreadRun();
Thread thread = new Thread(mThRun);
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//mThRun.foo(); //This works
//mThRun.notify(); //crash
//thread.notify();//crash
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
new ThreadingDemo().Start();
}
This is simple code to demonstrate wait() and notify(),
In the myThreadRun class run() method just does wait() and foo() method does notify()
as indicated in the code above, if I do mThRun.notify() the program crashes, but mThRun.foo() runs the without a hitch and gives the much needed result. I need to know why?
You need to own the monitor for the object to all obj.wait() and obj.notify().
That is why it works when called within the synchronized block on mThRun but not outside. So if you put the mThRun.notify(); in a synchronized block, it works, like this:
synchronized (mThRun) {
mThRun.notify();
}
In your case you are getting an IllegalMonitorStateException.
Thrown to indicate that a thread has attempted to wait on an object's monitor or to notify other threads waiting on an object's monitor without owning the specified monitor.
Put another way, you don't hold the lock of the object you are trying to notify. Having the lock of a different object doesn't help.
When you use notify() and wait() you need to change a state and check for it. If you don't do this, you can find that either
notify() is called before wait() and the signal is lost
wait() wakes prematurely
You cannot assume notify/wait is a reliable messaging protocol.
I suggest you consider using the concurrency library which is a better choice in most cases from Java 5.0 (2004)
May be you are going very hard with wait/notify. Its very simple. what you need to know is which object is used for monitor lock. To make the same code working i have modified the same code: ( I have put MAK comment where i changed the code, hope its helpful)
class MyThreadRun implements Runnable {
public void run() {
roo();
}
public synchronized void roo() {
System.out.println("In thread before wait " + this);
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
JOptionPane.showMessageDialog(null, "After wait in\n" + Thread.currentThread().getName());
System.out.println("In thread after wait " + Thread.currentThread().getName());
}
}
public class ThreadingDemo {
public static void main(String[] args) {
MyThreadRun mThRun = new MyThreadRun();
System.out.println("Labamba: " +mThRun);
Thread thread = new Thread(mThRun);
thread.start();
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
//mThRun.foo(); //This works //MAK: no sense
//mThRun.notify(); //crash //MAK: Need monitor lock
synchronized (mThRun) {
mThRun.notify();//crash //MAK: will work now
}
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}