RMI: Proper synchronization when Server is accessed by multiple clients - java

I started working with Java RMI a couple of days ago. I am wondering if the following example is properly synchronized.
Consider the following Server class which provides resource strings to clients. It shall never provide the same resource twice, therefor it stores the provided strings in a list. This is the ServerEngine class:
package dummy;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.LinkedList;
public class ServerEngine implements Server {
private final String s1 = "Resource Object 1";
private final String s2 = "Resource Object 2";
private final LinkedList<String> list = new LinkedList<>();
private final int timer = 5000;
public static void main(String[] args) {
try {
String name = "server";
ServerEngine engine = new ServerEngine();
Server stub = (Server) UnicastRemoteObject.exportObject(engine, 0);
Registry registry = LocateRegistry.getRegistry();
registry.rebind(name, stub);
System.out.println("ServerEngine bound");
} catch (Exception e) {
System.err.println("ServerEngine exception:");
}
}
#Override
public String getResource() throws RemoteException {
Object lock = new Object();
if ( ! list.contains(s1)) {
synchronized (lock) {
// wait to ensure concurrency
try {
lock.wait(timer);
} catch (InterruptedException ex) {}
}
list.add(s1);
return s1;
}
if ( ! list.contains(s2)) {
list.add(s2);
return s2;
}
return null;
}
}
The Server interface:
package dummy;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Server extends Remote {
public String getResource(boolean synced) throws RemoteException;
}
and the Client:
package dummy;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client {
public static void main(String[] args) {
try {
String name = "server";
Registry registry = LocateRegistry.getRegistry();
Server server = (Server) registry.lookup(name);
boolean sync = args.length > 0;
String s = server.getResource(sync);
System.out.println("Resource: " + s);
} catch (Exception e) {
System.err.println("Client exception:");
}
}
}
The ServerEngine is implemented in such a way that it will cause a concurrency issue. If two clients are started from two different VMs within five seconds then they both will get the same String returned.
From what I have researched so far, this is my approach to solve the issue:
package dummy;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.LinkedList;
public class ServerEngine implements Server {
private final String s1 = "Resource Object 1";
private final String s2 = "Resource Object 2";
private final LinkedList<String> list = new LinkedList<>();
private final int timer = 5000;
public static void main(String[] args) {
try {
String name = "server";
ServerEngine engine = new ServerEngine();
Server stub = (Server) UnicastRemoteObject.exportObject(engine, 0);
Registry registry = LocateRegistry.getRegistry();
registry.rebind(name, stub);
System.out.println("ServerEngine bound");
} catch (Exception e) {
System.err.println("ServerEngine exception:");
}
}
private synchronized String localGetResource() {
Object lock = new Object();
if ( ! list.contains(s1)) {
synchronized (lock) {
// wait to ensure concurrency
try {
lock.wait(timer);
} catch (InterruptedException ex) {}
}
list.add(s1);
return s1;
}
if ( ! list.contains(s2)) {
list.add(s2);
return s2;
}
return null;
}
#Override
public String getResource() throws RemoteException {
return localGetResource();
}
}
I would like to know if this is a feasible solution. Are there any caveats? Do I actually need a second function or could I synchronize getResource() directly?

Your synchronization is broken on several levels:
You're not supposed to wait() on something unless you expect some other thread to notify() you.
You're implementing only half of double-checked locking, which translates to "no locking", as the same value may end up in the list several times.
You should have a look at proper thread-safe collection implementations under java.util.concurrent, rather than doing this by hand.

Your locally create lock object is useless, as tsolakp noted, every method call creates its own instance.
Create the object as a field in order to use it's monitor for sychronization.
If you declare a method as synchronized you've use implicitly the monitor of the instance the method is invoked on. It makes no sense to mix these two approaches.
If you want to synchronize the access to your list use the according object's monitor for synchronization.

I am wondering if the following example is properly synchronized.
It isn't synchronized at all. It uses a lock, but not correctly, so it isn't sequentialized either.
public String getResource() throws RemoteException {
Object lock = new Object();
if ( ! list.contains(s1)) {
synchronized (lock) {
// wait to ensure concurrency
try {
lock.wait(timer);
} catch (InterruptedException ex) {}
}
list.add(s1);
return s1;
}
if ( ! list.contains(s2)) {
list.add(s2);
return s2;
}
return null;
}
You don't need all this, and you certainly don't need the wait(). This code will never actually lock the list effectively, because every invocation gets its own lock object.
Throw it all away and just synchronize the method:
public synchronized String getResource() throws RemoteException {
if ( ! list.contains(s1)) {
list.add(s1);
return s1;
}
if ( ! list.contains(s2)) {
list.add(s2);
return s2;
}
return null;
}

Related

Semaphores not avoiding thread loss

this is my first question here so please bear with me.
I am currently working on a UNI assignment on multithreading and concurrency in Java where we are asked to implement various versions of a "Call Center" using different thread locking methods, with one of them being Semaphores. I'll get right into the code to show what my problem is:
Producer Class:
public final class Caller implements Runnable {
private final CallCenter callCenter;
public Caller(long id, CallCenter callCenter) {
this.callCenter = callCenter;
}
#Override
public void run() {
try {
callCenter.receive(new Call());
} catch(Exception ex) {
throw new RuntimeException(ex);
}
}
}
Consumer Class:
public final class Operator implements Runnable {
private final CallCenter callCenter;
private Call call;
public Operator(CallCenter callCenter) {
this.callCenter = callCenter;
}
#Override
public void run() {
try {
this.call = callCenter.answer();
} catch(InterruptedException ex) {
throw new RuntimeException(ex);
}
}
public Call getCall() {
return this.call;
}
}
Service:
import java.util.Queue;
import java.util.concurrent.Semaphore;
import java.util.LinkedList;
public final class BoundedCallCenterSemaphore implements BoundedCallCenter {
private final Queue<Call> pendingCalls = new LinkedList<Call>();
private Semaphore semaphore = new Semaphore(MAX_NUMBER_OF_PENDING_CALLS, true);
public void receive(Call call) throws Exception {
semaphore.acquire();
pendingCalls.add(call);
}
public Call answer() throws InterruptedException {
semaphore.release();
return pendingCalls.poll();
}
}
Call Implementation:
import java.util.concurrent.atomic.AtomicLong;
public final class Call {
private static final AtomicLong currentId = new AtomicLong();
private final long id = currentId.getAndIncrement();
public long getId() {
return id;
}
}
Disclaimer
I know I am probably not using the semaphore the way it is intended to be used, but reading the official docs an other blogs/answers does not help at all.
We have the following constraints: only modify the Service Class, solve using Semaphores and only use Semaphore.acquire() and Semaphore.receive() to avoid racing and busy waiting, no other method or thread-locking structure is allowed
Actual Problem:
I'll avoid posting here the entirety of the tests written by our professor, just know that 100 calls are sent to the Service, for simplicity each caller only calls once and each operator only responds once. When implementing the callcenter without semaphores you'll get busy waits generated by a while loop and concurrency is not well-managed as some calls can be answered twice or more if the different threads act simultaneously. The mission here is to eliminate busy waits and ensure each call is received and answered only once. I tried using semaphores as reported above, and while busy wait is eliminated some of the calls end up not being answered at all. Any advice on what I am doing wrong? How do I ensure that each and every call is answered only once?
In the end, I did it using three semaphores. The first semaphore new Semaphore(MAX_NUMBER_OF_PENDING_CALLS, true) guards the queue in the sense of blocking new entries when pendingCalls.size() >= MAX_NUMBER_OF_PENDING_CALLS . The second semaphore new Semaphore(1, true) guards the producer threads, allowing just one thread at a time to access the queue for adding operations. The third and last semaphore starts with no permits and waits for the first producer thread to insert the first call into the buffer new Semaphore(0, true) .
Code
public final class BoundedCallCenterSemaphore implements BoundedCallCenter {
private final LinkedList<Call> pendingCalls = new LinkedList<Call>();
static Semaphore receiver = new Semaphore(1, true);
static Semaphore storage = new Semaphore(MAX_NUMBER_OF_PENDING_CALLS, true);
static Semaphore operants = new Semaphore(0, true);
public void receive(Call call) throws Exception {
try {
storage.acquire();
}
catch (InterruptedException e)
{
}
try {
receiver.acquire();
}
catch (InterruptedException e)
{
}
synchronized (pendingCalls) {
pendingCalls.add(call);
operants.release();
}
}
public Call answer() throws InterruptedException {
try
{
operants.acquire();
}
catch (InterruptedException e)
{
}
Call call = null;
synchronized (pendingCalls) {
call = pendingCalls.poll();
storage.release();
receiver.release();
}
return call;
}
}

Synchronize by value rather that object

I implemented a simple locking solution that creates a lock for a value rather than object and want to know the experts' opinion for possible performance or security drawbacks.
The idea is to use it for account balance update acquiring the lock for unique account number.
Here is an implementation:
import java.util.*;
public class Mutex<T> {
private final Set<T> set = new HashSet();
public synchronized Lock acquireLock(
T value
) throws InterruptedException {
while(!set.add(value)) {
this.wait();
}
return new Lock(value);
}
public class Lock {
private final T value;
public Lock(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public void release() {
synchronized(Mutex.this) {
set.remove(value);
Mutex.this.notifyAll();
}
}
}
}
And here is a sample usage to check the operability:
public class Test {
private Mutex mutex = new Mutex();
public static void main(String[] args) {
Test test = new Test();
Thread t1 = new Thread(() -> {
try {
test.test("SameValue");
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
t1.setName("Thread 1");
Thread t2 = new Thread(() -> {
try {
test.test("SameValue");
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
t2.setName("Thread 2");
t1.start();
t2.start();
}
public void test(String value)
throws
InterruptedException {
Lock lock = mutex.acquireLock(value);
try {
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName());
} finally {
lock.release();
}
}
}
Regarding your implementation,
I would have use a Set instead of a List to hold your values (I assume the values have proper equals/hashcode for this to make sense): the List#contains method is in O(n) which might be expensive if you have a lot of IBAN used at the same time.
Also, you should avoid using synchronize(this) (which is the same as the synchronized keyword on method).
To solve your problem, I use something like this:
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Locks<T> {
private final Lock lock = new ReentrantLock();
//a Bimap from guava might be better here if you have the dependency
//in your project
private final Map<Reference<?>, T> valuePerReference = new HashMap<>();
private final Map<T, Reference<Lock>> locks = new HashMap<>();
private final ReferenceQueue<Lock> lockReferenceQueue = new ReferenceQueue<>();
public Locks() {
final Thread cleanerThread = new Thread(new Cleaner());
cleanerThread.setDaemon(true);
cleanerThread.start();
}
/**
* #param value the value the synchronization must be made on
* #return a lock that can be used to synchronize block of code.
*/
public Lock getLock(T value) {
lock.lock();
try {
return getExistingLock(value).orElseGet(() -> createNewLock(value));
} finally {
lock.unlock();
}
}
private Optional<Lock> getExistingLock(T value) {
return Optional.ofNullable(locks.get(value)).map(Reference::get);
}
private Lock createNewLock(T value) {
//I create ReentrantLock here but a Supplier<Lock> could be a parameter of this
//class to make it more generic. Same remark for SoftReference below.
final Lock lock = new ReentrantLock();
final Reference<Lock> reference = new SoftReference<>(lock, lockReferenceQueue);
this.locks.put(value,reference);
this.valuePerReference.put(reference,value);
return lock;
}
private void removeLock(Reference<?> reference) {
lock.lock();
try {
final T value = valuePerReference.remove(reference);
locks.remove(value);
} finally {
lock.unlock();
}
}
private class Cleaner implements Runnable {
#Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
final Reference<? extends Lock> garbaged = lockReferenceQueue.remove();
removeLock(garbaged);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
}
I then use this like this:
import java.util.concurrent.locks.Lock;
public class Usage {
private final Locks<String> locks = new Locks<>();
public void doSomethind(String iban) {
final Lock lock = locks.getLock(iban);
lock.lock();
try {
//.. do something with your iban
} finally {
lock.unlock();
}
}
}
Although it uses ReentrantLock, the code can be easily modified for ReadWriteLock for instance.

Algorithm - execute task only for unique entries in queue, common entries should wait

We are creating a rest application. And we have an edge condition where parallel actions are not supported on same object.
For example :
Not supported in parallel
Request 1 for action XYZ for object A
Request 2 for action XYZ for object A
Request 3 for action ABC for object A
Supported in parallel
Request 1 for action XYZ for object A
Request 2 for action XYZ for object B
Request 3 for action ABC for object C
Now, the object count is not fixed. we can have n number of such objects.
I want that if a request for object A is under progress then other request for object A should wait for existing task on object A to get over.
But I am not able to figure out the algorithm for this purpose.
I could plan for below design but not able to figure out on how to use the locking since all objects can be different.
A queue which stores the entry for object A when request comes.
Entry gets deleted if response is sent
If an entry is already present, then wait for existing request to get over.
If entry not present, then execute immediately.
Now task on object A should not impact the task on object B. So they must accept unique locks.
And also, request cannot go standalone and be queued. Somehow I have to make the current thread sleep so that I can send response to user.
Can anyone guide here?
UPDATED based on comments from my original response
The ideal model for something like that would be using an actor system such as Akka.
But your comment states that this will happen in the context on a REST application where threads will be blocked already by request processing.
In this case, the idea would be using a per-object-guard such as:
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
public class ObjectGuard<K> {
private final ConcurrentMap<K, CountDownLatch> activeTasks = new ConcurrentHashMap<>();
public Guard guardFor(final K key) throws InterruptedException {
if (key == null) {
throw new NullPointerException("key cannot be null");
}
final CountDownLatch latch = new CountDownLatch(1);
while (true) {
final CountDownLatch currentOwner = activeTasks.putIfAbsent(key, latch);
if (currentOwner == null) {
break;
} else {
currentOwner.await();
}
}
return () -> {
activeTasks.remove(key);
latch.countDown();
};
}
public interface Guard extends AutoCloseable {
#Override
void close();
}
}
You would use it as follows:
class RequestProcessor {
private final ObjectGuard<String> perObjectGuard = new ObjectGuard<>();
public String process(String objectId, String op) throws InterruptedException {
// Only one thread per object id can be present at any given time
try (ObjectGuard.Guard ignore = perObjectGuard.guardFor(objectId)) {
String result = ... // compute response
}
}
}
If two concurrent calls to process are received for the same object id, only one will be processed, the others wait their turn to process a request on that object.
An object which executes requests serially is known as Actor. The most widely known java actor library is named Akka. The most simple (one page) actor implementation is my SimpleActor.java.
Signalling like juancn does in his answer is not my strong suit, so I made an even cruder solution using one Semaphore for signalling combined with a request-counter.
There is one lock involved (subjectsLock) which synchronizes everything at one point in time. The lock is required to ensure there are no memory leaks: since there can be any number of subjects (a.k.a. object identifiers in your question), cleanup is essential. And cleanup requires knowing when something can be removed and that is difficult to determine without a lock that brings everything to one known state at a certain point in time.
The test in the main-method in the code shown below is a bit hard to read, but it serves as a starting point for a demonstration of how the code works internally. The main logic is in the methods executeRequest, addSubject and removeSubject. If those three methods do not make sense, another solution should be used.
Stress-testing will have to determine if this solution is fast enough: it depends on the number of requests (per second) and the amount of time it takes to complete an action. If there are many requests and the action is short/fast, the (synchronization) overhead from the lock could be to high.
// package so;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.IntStream;
public class RequestQueue {
public static void main(String[] args) {
// Randomized test for "executeRequest" method below.
final int threadCount = 4;
ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);
try {
final int requestCount = 100;
final RequestQueue rq = new RequestQueue();
final Random random = new Random();
IntStream.range(0, requestCount).forEach(i -> threadPool.execute(new Runnable() {
#Override
public void run() {
try {
String subject = "" + (char) (((int)'A') + random.nextInt(threadCount));
rq.executeRequest(subject, new SleepAction(i, subject, 50 + random.nextInt(5)));
} catch (Exception e) {
e.printStackTrace();
}
}
}));
sleep(100); // give threads a chance to start executing.
while (true) {
sleep(200);
List<String> subjects = rq.getSubjects();
System.out.println("Subjects: " + subjects);
if (subjects.isEmpty()) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();
}
}
private Map<String, QueueLock> subjects = new LinkedHashMap<>();
// a fair ReentrantLock is a little bit slower but ensures everybody gets their turn in orderly fashion.
private final ReentrantLock subjectsLock = new ReentrantLock(true);
private class QueueLock {
// a fair Semaphore ensures all requests are executed in the order they arrived.
final Semaphore turn = new Semaphore(1, true);
final AtomicInteger requests = new AtomicInteger(1);
public String toString() { return "request: " + requests.get(); }
}
/**
* Allow all requests for different subjects to execute in parallel,
* execute actions for the same subject one after another.
* Calling thread runs the action (possibly after waiting a bit when an action for a subject is already in progress).
*/
public String executeRequest(String subject, Runnable action) throws InterruptedException {
QueueLock qlock = addSubject(subject);
try {
int requestsForSubject = qlock.requests.get();
if (requestsForSubject > 1) {
System.out.println(action.toString() + " waiting for turn " + requestsForSubject);
}
qlock.turn.acquire();
if (requestsForSubject > 1) {
System.out.println(action.toString() + " taking turn " + qlock.requests.get());
}
action.run();
} catch (Exception e) {
e.printStackTrace();
} finally {
removeSubject(subject);
}
return timeSinceStart() + " " + subject;
}
private QueueLock addSubject(String s) {
QueueLock qlock = null;
subjectsLock.lock();
try {
qlock = subjects.get(s);
if (qlock == null) {
qlock = new QueueLock();
subjects.put(s, qlock);
} else {
qlock.requests.incrementAndGet();
}
} finally {
subjectsLock.unlock();
}
return qlock;
}
private boolean removeSubject(String s) {
boolean removed = false;
subjectsLock.lock();
try {
QueueLock qlock = subjects.get(s);
if (qlock.requests.decrementAndGet() == 0) {
subjects.remove(s);
removed = true;
} else {
qlock.turn.release();
}
} finally {
subjectsLock.unlock();
}
return removed;
}
public List<String> getSubjects() {
List<String> subjectsBeingProcessed = new ArrayList<>();
subjectsLock.lock();
try {
// maintains insertion order, see https://stackoverflow.com/a/18929873/3080094
subjectsBeingProcessed.addAll(subjects.keySet());
} finally {
subjectsLock.unlock();
}
return subjectsBeingProcessed;
}
public static class SleepAction implements Runnable {
final int requestNumber;
final long sleepTime;
final String subject;
public SleepAction(int requestNumber, String subject, long sleepTime) {
this.requestNumber = requestNumber;
this.sleepTime = sleepTime;
this.subject = subject;
}
#Override
public void run() {
System.out.println(toString() + " sleeping for " + sleepTime);
sleep(sleepTime);
System.out.println(toString() + " done");
}
public String toString() {return timeSinceStart() + " " + subject + " [" + Thread.currentThread().getName() + "] " + String.format("%03d",requestNumber); }
}
public static final long START_TIME = System.currentTimeMillis();
public static String timeSinceStart() {
return String.format("%05d", (System.currentTimeMillis() - START_TIME));
}
public static void sleep(long milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

Java - Synchronized

Hi i have made a something that extends thread that adds adds an object that has a IP in it. then i made two instances of this thread and started them. they use the same list.
I now want to use Synchronized to stop the concurrent update problem. But its not working and i cant work out why.
My main class:
import java.util.*;
import java.io.*;
import java.net.*;
class ListTest2 {
public static LinkedList<Peer> myList = new LinkedList<Peer>();
public static void main(String [] args) {
try {
AddIp test1 = new AddIp(myList);
AddIp test2 = new AddIp(myList);
test1.start();
test2.start();
} catch(Exception e) {
System.out.println("not working");
}
}
}
My thread class:
class AddIp extends Thread {
public static int startIp = 0;
List<Peer> myList;
public AddIp(List<Peer> l) {
myList = l;
}
public synchronized void run() {
try {
startIp = startIp+50;
int ip = startIp;
InetAddress address = InetAddress.getByName("127.0.0.0");
Peer peer = new Peer(address);
while(ip <startIp+50) {
ip++;
address = InetAddress.getByName("127.0.0."+ip);
peer = new Peer(address);
myList.add(peer);
if(myList.indexOf(peer)== (myList.size() -1)) {
} else {
System.out.println("Lost"+peer.peerIp);
}
}
} catch(Exception e) {
}
}
}
Can anyone help me out here im lost for ideas thanks.
public synchronized void run()
Synchronizes on calling instance: this.
So,
1st thread synchronizes on test1 and 2nd thread synchronizes on test2, which doesn't help at all.
You want to synchronize on the shared resource, in this case: myList
public void run() {
synchronize(myList){
//your Logic
}
}
As a side note: Implement runnable instead of extending a Thread. Read more here.
You'd be better off implementing Runnable oppose to extending thread
also
public void run() {
synchronize(list){
//stuffs
}
}
they use the same list.
You can try to use Vector instead List. Vector is synchronized
or set your List to be synchronized:
List myList = Collections.synchronizedList(myList);
instead to use:
synchronize(myList){
}
The easiest way is to use a List implementation that can handle multiple threads. Try CopyOnWriteArrayList.

getting thread names in stop() method

how can I get in stop() thread names like i did in start()? Thread names are A,B,C,D. My program runs thread in order and stops them in revers order. But I have problem with printing their names. In start() I do it without any problems but in stop() I just dont know how to do it. I'm pretty new in java and this is one of my firs programs that I did that is why i dont know how to do this.
Thank you so much for your help.
Here is the code:
import java.util.*;
class Service extends Thread
{
private RobotController controller;
public String robotID;
private byte[] lock;
public Service(RobotController cntrl, String id)
{
controller = cntrl;
robotID = id;
}
public byte[] getLock() { return lock;}
public void run()
{
lock = new byte[0];
synchronized(lock)
{
byte[] data;
while ((data = controller.getData()) == null)
{
try {
lock.wait();
} catch (InterruptedException ie) {}
}
System.out.println("Thread " + robotID + " Working" );
}
}
}
class RobotController
{
private byte[] robotData;
private Vector threadList = new Vector();
private Service thread_A;
private Service thread_B;
private Service thread_C;
private Service thread_D;
public void setup(){
thread_A = new Service(this, "A");
thread_B = new Service(this, "B");
thread_C = new Service(this, "C");
thread_D = new Service(this, "D");
threadList.addElement(thread_A);
threadList.addElement(thread_B);
threadList.addElement(thread_C);
threadList.addElement(thread_D);
thread_A.start();
thread_B.start();
thread_C.start();
thread_D.start();
start();
stop();
}
public void start()
{
System.out.println("START:");
{
for (int i=0; i <threadList.size(); i++)
{
try {
Thread.sleep(500);
}catch (InterruptedException ie){
System.out.println(ie);
}
putData(new byte[10]);
Service rbot = (Service)threadList.elementAt(i);
byte[] robotLock = rbot.getLock();
synchronized(robotLock) {
robotLock.notify();
}
}
}
}
public void stop()
{
Collections.reverse(threadList);
System.out.println("STOP:");
for ( Object o : threadList) {
System.out.println("Thread "+ o +" Stop");
}
}
public synchronized byte[] getData()
{
if (robotData != null)
{
byte[] d = new byte[robotData.length];
System.arraycopy(robotData, 0, d, 0, robotData.length);
robotData = null;
return d;
}
return null;
}
public void putData(byte[] d) { robotData = d;}
public static void main(String args[])
{
RobotController controller = new RobotController();
controller.setup();
}
}
Thread has name and getter getName(), so if you have instance of thread you can always call thread.getName().
I do not know how do you access the thread name "in start" because I do not see where do you call getName(). However I think I know what's your problem in stop.
You store your threads in Vector. Then you iterate over vector's elements and print thread, so it invokes thread's toString(). You probably have to cast Object to Thread and call its getName():
System.out.println("STOP:");
for ( Object o : threadList) {
System.out.println("Thread "+ ((Thread)o).getName() +" Stop");
}
But once you are done, I'd recommend you to find a good and new enough tutorial on java.
You are using not commonly applicable coding formatting.
You are using Vector instead of List and its implementations.
You are trying to use unclear technique for thread synchronization and management.
Start learning step-by-step. And do not hesitate to ask questions. Good luck.

Categories