Following is some parts of my code, which uses Threading. The purpose is to retrieve all the records from database (approx. 5,00,000) and send them alert email messages. The problem I am facing is the variable emailRecords becomes very heavy and too much time is taken to send email message. How can I make it fast by using multi-threading such that 5,00,000 records are processed parallelly? I tried to use ExecutorService but got confused in implementing it. I got mixed up in the method checkName(), getRecords() and sendAlert(). All these 3 methods are used relevantly. So, where to use executorService ??
Please provide me the suggestion how to proceed with the following code and which part needs editing? Thanks in advance!!
public class sampledaemon implements Runnable {
private static List<String[]> emailRecords = new ArrayList<String[]>();
public static void main(String[] args) {
if (args.length != 1) {
return;
}
countryName = args[0];
try {
Thread t = null;
sampledaemon daemon = new sampledaemon();
t = new Thread(daemon);
t.start();
} catch (Exception e) {
e.printStackTrace()
}
}
public void run() {
Thread thisThread = Thread.currentThread();
try {
while (true) {
checkName(countryName);
Thread.sleep(TimeUnit.SECONDS.toMillis(10));
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void checkName(String countryName) throws Exception {
Country country = CountryPojo.getDetails(countryName)
if (country != null) {
getRecords(countryconnection);
}
}
private void getRecords(Country country, Connection con) {
String users[] = null;
while (rs.next()) {
users = new String[2];
users[0] = rs.getString("userid");
users[1] = rs.getString("emailAddress");
emailRecords.add(props);
if (emailRecords.size() > 0) {
sendAlert(date, con);
}
}
}
void sendAlert(String date, Connection con) {
for (int k = 0; k < emailRecords.size(); k++) {
//check the emailRecords and send email
}
}
}
From what i can tell is that you would most likely be single threaded data retrieval, and multi-threaded for the e-mail sending. Roughly, you'd be cycling through your result set and building a list of records. When that list hits a certain size, you make a copy and send off that copy to be processed in a thread, and clear the original list. At the end of the result set, check to see if you have unprocessed records in your list, and send that to the pool as well.
Finally, wait for the threadpool to finish processing all records.
Something along these lines:
protected void processRecords(String countryName) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 10, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(5), new ThreadPoolExecutor.CallerRunsPolicy());
List<String[]> emaillist = new ArrayList<String>(1000);
ResultSet rs = ....
try {
while (rs.next()) {
String user[] = new String[2];
users[0] = rs.getString("userid");
users[1] = rs.getString("emailAddress");
emaillist.add(user);
if (emaillist.size() == 1000) {
final List<String[]> elist = new ArrayList<String[]>(emaillist);
executor.execute(new Runnable() {
public void run() {
sendMail(elist);
}
}
emaillist.clear();
}
}
}
finally {
DbUtils.close(rs);
}
if (! emaillist.isEmpty()) {
final List<String[]> elist = emaillist;
executor.execute(new Runnable() {
public void run() {
sendMail(elist);
}
}
emaillist.clear();
}
// wait for all the e-mails to finish.
while (! executor.isTerminated()) {
executor.shutdown();
executor.awaitTermination(10, TimeUnit.DAYS);
}
}
The advantage of using the FixedThreadPool is that you don't have to do the expensive process of creating the threads again and again, its done at the beginning...see below..
ExecutorService executor = Executors.newFixedThreadPool(100);
ArrayList<String> arList = Here your Email addresses from DB will go in ;
for(String s : arList){
executor.execute(new EmailAlert(s));
}
public class EmailAlert implements Runnable{
String addr;
public EmailAlert(String eAddr){
this.addr = eAddr;
}
public void run(){
// Do the process of sending the email here..
}
}
Creating a second thread to do all of the work in instead of doing the same work in the main thread isn't going to help you avoid the problem of filling up the emailRecords list with 5 million records before processing any of them.
It sounds like your goal is to be able to read from the database and send email in parallel. Instead of worrying about the code, first think of an algorithm for the work you want to accomplish. Something like this:
In one thread, query for the records from the database, and for each result, add one job to an ExecutorService
That job sends email to one person/address/record.
or alternatively
Read records from the database in batches of N (50, 100, 1000, etc)
Submit each batch to the executorService
Related
I'm writing an IP scanner application and the process is taking long time so what i used at back scene of gui is service executor like:
public static List<Future<String>> checkThisIP(String ipStart, String ipEnd) throws UnknownHostException {
final ExecutorService es = Executors.newFixedThreadPool(10);
final List<Future<String>> futures = new ArrayList<>();
String ipStringStart;
String ipStringEnd;
String targetIpString;
//my update
ipStringStart = ipStart.substring(ipStart.lastIndexOf(".") + 1, ipStart.length());
ipStringEnd = ipEnd.substring(ipEnd.lastIndexOf(".") + 1, ipEnd.length());
targetIpString = ipStart.substring(0, ipStart.lastIndexOf(".") + 1);
if (!ipStart.equals(ipEnd)) {
for (int i = Integer.parseInt(ipStringStart); i <= Integer.parseInt(ipStringEnd); i++) {
String currentIp = targetIpString + i;
futures.add(runPingScan(es, currentIp));
}
} else {
futures.add(runPingScan(es, ipStart));
}
es.shutdown();
return futures;
}
public static Future<String> runPingScan(final ExecutorService es, final String ip) {
return es.submit(new Callable<String>() {
#Override
public String call() {
String returnMe = "";
//custom ping class
Ping p = new Ping();
//send message
p.SendReply(ip);
//IsReachable returns ture or false
if(p.IsReachable()){
returnMe=ip;
}
return returnMe;
}
});
}
This is the original laggy code action preformed using Jbutton:
// scan result is Future list returned from service executor
List<Future<String>> scanResult = p.checkThisIP(jFormattedTextField1.getText(), jFormattedTextField2.getText());
for (final Future<String> f : scanResult) {
try {
ip = f.get();
if (!ip.equals("")) {
arp ARP = new arp();
PortScan openPort = new PortScan();
IP ipClass = new IP();
mac = ARP.getMac(ip);
manufacturer = ARP.getOUI(mac);
ports = openPort.checkIpForPorts(ip);
hostname = ipClass.hostname(ip);
title = ipClass.htmlTitle(ip);
Object[] data = {ip, mac, manufacturer, ports, hostname, title};
tableModel.addRow(data);
}
if (jFormattedTextField1.getText().equals(jFormattedTextField2.getText()) && ip.equals("")) {
JOptionPane.showMessageDialog(null, "<html>Can not ping the address ! <br> Server might be protected by <b>WAF</b>.</html>", "Alert", HEIGHT);
}
} catch (Exception ex) {
Logger.getLogger(gui.class.getName()).log(Level.SEVERE, null, ex);
}
}
Running this code is good but when i attach it to Start Scan Button the gui lags, I googled and figured out to use Swing Worker. When i implemented the swing worker alone it killed the concurrency and when i implemented both the gui still lags. My question is there anyway to make the button (Swing worker) call the service executor to do the other processes ?
I've managed to solve my problem by implementing the swing worker and the function do in back ground will start a new thread for service executor and prevent the lag.
//The actionpreformed by the button
SwingWorker worker = new SwingWorker<Void, Void>() {
#Override
// All actions are done this method
protected Void doInBackground() throws Exception {
String ip = "";
String mac = "";
String manufacturer = "";
String ports = "";
String hostname = "";
String title = "";
tableModel.setRowCount(0);
PingScan p = new PingScan();
List<Future<String>> scanResult = p.checkThisIP(jFormattedTextField1.getText(), jFormattedTextField2.getText());
for (final Future<String> f : scanResult) {
try {
ip = f.get();
if (!ip.equals("")) {
arp ARP = new arp();
PortScan openPort = new PortScan();
IP ipClass = new IP();
mac = ARP.getMac(ip);
manufacturer = ARP.getOUI(mac);
ports = openPort.checkIpForPorts(ip);
hostname = ipClass.hostname(ip);
title = ipClass.htmlTitle(ip);
Object[] data = {ip, mac, manufacturer, ports, hostname, title};
tableModel.addRow(data);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
return null;
}
};
worker.execute();
When i implemented the swing worker alone it killed the concurrency and when i implemented both the gui still lags.
There's two things to do here:
spreading your ping checks over multiple threads
split your task into independent sub-tasks
run sub-tasks in a thread-pool
collect results
detaching the whole operation from the event dispach thread
register user action (click, keypress), get data from text fields, build task
run task outside of the EDT
update the gui, showing the results
You're doing the first part with the ExecutorService, for some of your code. The second part is not done in your code, so the EDT will block until the whole operation is finished, making your gui lag.
You'll need to move this code to a swing worker, which runs the tasks in the executor:
List<Future<String>> scanResult = p.checkThisIP(jFormattedTextField1.getText(), jFormattedTextField2.getText());
for (final Future<String> f : scanResult) {
try {
[...] // this is where the thread blocks, making your ui lag if it's the EDT
Object[] data = {ip, mac, manufacturer, ports, hostname, title};
First, move all blocking code to be handled by the executor's thread pool:
public static Future<Object[]> runPingScan(final ExecutorService es, final String ip) {
return es.submit(new Callable<Object[]>() {
#Override
public Object[] call() {
//custom ping class
Ping p = new Ping();
//send message
p.SendReply(ip);
//IsReachable returns ture or false
if(p.IsReachable()){
[...] // other blocking code
return {ip, mac, manufacturer, ports, hostname, title};
} else {
// special case, use null values or throw an exception
}
}
});
}
Then you can use the Simple Background Tasks tutorial code to detach the whole thing from the EDT:
SwingWorker worker = new SwingWorker<List<Object[]>, Void>() {
public List<Object[]> doInBackground() {
// -- this will run in another thread --
// submit ping checks to the executor
List<Future<Object[]>> scanResult = [...]
// get results, put them in a list, return it
List<Object[]> result = new ArrayList<>();
for(Future<Object[]> f : scanResult) {
result.add(f.get()); // blocking happens here, outside of the EDT
}
return result;
}
public void done() {
// -- this will run in the EDT --
// get() the list created above
// display the result in the gui
for(Object[] data : get()) {
tableModel.addRow(data);
}
}
};
What's not included here are special cases like a failed ping check, you'll need to handle them somehow. Every exception thrown from within your callables is rethrown when calling f.get(), wrapped in an ExecutionException. Using that for those special cases is probably your best option.
I have the following work queue implementation, which I use to limit the number of threads in use. It works by me initially adding a number of Runnable objects to the queue, and when I am ready to begin, I run "begin()". At this point I do not add any more to the queue.
public class WorkQueue {
private final int nThreads;
private final PoolWorker[] threads;
private final LinkedList queue;
Integer runCounter;
boolean hasBegun;
public WorkQueue(int nThreads) {
runCounter = 0;
this.nThreads = nThreads;
queue = new LinkedList();
threads = new PoolWorker[nThreads];
hasBegun = false;
for (int i = 0; i < nThreads; i++) {
threads[i] = new PoolWorker();
threads[i].start();
}
}
public boolean isQueueEmpty() {
synchronized (queue) {
if (queue.isEmpty() && runCounter == 0) {
return true;
} else {
return false;
}
}
}
public void begin() {
hasBegun = true;
synchronized (queue) {
queue.notify();
}
}
public void add(Runnable r) {
if (!hasBegun) {
synchronized (queue) {
queue.addLast(r);
runCounter++;
}
} else {
System.out.println("has begun executing. Cannot add more jobs ");
}
}
private class PoolWorker extends Thread {
public void run() {
Runnable r;
while (true) {
synchronized (queue) {
while (queue.isEmpty()) {
try {
queue.wait();
} catch (InterruptedException ignored) {
}
}
r = (Runnable) queue.removeFirst();
}
// If we don't catch RuntimeException,
// the pool could leak threads
try {
r.run();
synchronized (runCounter) {
runCounter--;
}
} catch (RuntimeException e) {
// You might want to log something here
}
}
}
}
}
This is a runnable I use to keep track of when all the jobs on the work queue have finished:
public class QueueWatcher implements Runnable {
private Thread t;
private String threadName;
private WorkQueue wq;
public QueueWatcher(WorkQueue wq) {
this.threadName = "QueueWatcher";
this.wq = wq;
}
#Override
public void run() {
while (true) {
if (wq.isQueueEmpty()) {
java.util.Date date = new java.util.Date();
System.out.println("Finishing and quiting at:" + date.toString());
System.exit(0);
break;
} else {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(PlaneGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public void start() {
wq.begin();
System.out.println("Starting " + threadName);
if (t == null) {
t = new Thread(this, threadName);
t.setDaemon(false);
t.start();
}
}
}
This is how I use them:
Workqueue wq = new WorkQueue(9); //Get same results regardless of 1,2,3,8,9
QueueWatcher qw = new QueueWatcher(wq);
SomeRunnable1 sm1 = new SomeRunnable1();
SomeRunnable2 sm2 = new SomeRunnable2();
SomeRunnable3 sm3 = new SomeRunnable3();
SomeRunnable4 sm4 = new SomeRunnable4();
SomeRunnable5 sm5 = new SomeRunnable5();
wq.add(sm1);
wq.add(sm2);
wq.add(sm3);
wq.add(sm4);
wq.add(sm5);
qw.start();
But regardless of how many threads I use, the result is always the same - it always takes about 1m 10seconds to complete. This is about the same as when I just did a single threaded version (when everything ran in main()).
If I set wq to (1,2,3--9) threads it is always between 1m8s-1m10s. What is the problem ? The jobs (someRunnable) have nothing to do with each other and cannot block each other.
EDIT: Each of the runnables just read some image files from the filesystems and create new files in a separate directory. The new directory eventually contains about 400 output files.
EDIT: It seems that only one thread is always doing work. I made the following changes:
I let the Woolworker store an Id
PoolWorker(int id){
this.threadId = id;
}
Before running I print the id of the worker.
System.out.println(this.threadId + " got new task");
r.run();
In WorkQueue constructor when creating the poolworkers I do:
for (int i = 0; i < nThreads; i++) {
threads[i] = new PoolWorker(i);
threads[i].start();
}
But it seems that that only thread 0 does any work, as the output is always:
0 got new task
Use queue.notifyAll() to start processing.
Currently you're using queue.notify(), which will only wake a single thread. (The big clue that pointed me to this was when you mentioned only a single thread was running.)
Also, synchronizing on Integer runCounter isn't doing what you think it's doing - runCounter++ is actually assigning a new value to the Integer each time, so you're synchronizing on a lot of different Integer objects.
On a side note, using raw threads and wait/notify paradigms is complicated and error-prone even for the best programmers - it's why Java introduced the java.util.concurrent package, which provide threadsafe BlockingQueue implementations and Executors for easily managing multithreaded apps.
I'm trying to do a multi-get on my redis data store which is distributed across multiple shards. However the keys I want to do this on do not belong to the same shard so I can't use redis' inbuilt multi-get.
Instead I'm trying to use futures to achieve this. But after checking the lookup times it almost seems like these cache calls are being made serially.
The request/sec on the server is about 1.5k with an average of 10 ms response time. Literature I've read told me that my threadpool size should be requests/sec * response time. Since I'm spawning 3 threads this becomes 1500 * 0.010 * 3 = 45. I've tried using threadpool sizes of 50,100,300. But this hasn't helped either.
I'm using Jedis as a client. I thought it could be an issue with exceeding Jedis' max total/idle connection limit. But even after increasing this from 8 to 24 I see no difference in lookup times.
I understand that some overhead will be there since there will be context switches and the overhead of spawning new threads.
Can anyone help me figure out where I'm missing out. Let me know if you need more info.
for(String recordKey : pidArr) {
//Adding futures. Max 3
if(count >= 3) {
break;
}
count++;
Callable<String> a = new FeedCacheCaller(recordKey);
Future<String> future = feedThreadPool.submit(a);
futureList.add(future);
}
//Getting the data from the futures
for(Future<String> foo : futureList) {
try {
String data = foo.get();
logger.debug(data);
feedDataList.add(parseInfo(data));
} catch (Exception e) {
logger.error("somethings going wrong in retrieval",e);
}
}
Here's the Callable class
public class FeedCacheCaller implements Callable {
String pid = null;
FeedCache feedCache;
public FeedCacheCaller(String pid) {
this.pid = pid;
this.feedCache = new FeedCache();
}
#Override
public String call() throws Exception {
return feedCache.get(pid);
}
}
Edit 1:
Here's the Jedis side code.
public class FeedCache {
private ShardedJedisPool feedClient = RedisPool.getPool("feed");
public String get(String key) {
ShardedJedis client = null;
String value = null;
try {
client = feedClient.getResource();
byte[] valueByteArray = client.get(key.getBytes(Constants.CHARSET));
if (valueByteArray != null) {
value = new String(CacheUtils.decompress(valueByteArray),
Constants.CHARSET);
}
} catch (JedisConnectionException e) {
if (client != null) {
feedClient.returnBrokenResource(client);
client = null;
}
logger.error(e.getMessage());
} finally {
if (client != null) {
feedClient.returnResource(client);
}
}
return value;
}
}
Here is the code that initializes the ShardedJedisPool
public class RedisPool {
private static final Logger logger = LoggerFactory.getLogger(
RedisPool.class);
private static ConcurrentHashMap<String, ShardedJedisPool> redisPools = new ConcurrentHashMap<String, ShardedJedisPool>();
public static void initializePool(String poolName) {
List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
ArrayList<String> servers = new ArrayList<String>(Arrays.asList(
Constants.config.getStringArray(
poolName + "_redis_servers")));
for (int i = 0; i < servers.size(); i++) {
JedisShardInfo shardInfo = new JedisShardInfo(servers.get(i).split(":")[0], Integer.parseInt(servers.get(i).split(":")[1]));
shards.add(shardInfo);
}
redisPools.putIfAbsent(poolName,
new ShardedJedisPool(new GenericObjectPoolConfig(), shards));
}
public static ShardedJedisPool getPool(String poolName) {
if (!redisPools.containsKey(poolName)) {
synchronized (RedisPool.class) {
if (!redisPools.containsKey(poolName)) {
initializePool(poolName);
}
}
}
return redisPools.get(poolName);
}
public static void shutdown(String poolName) {
ShardedJedisPool pool = getPool(poolName);
pool.destroy();
redisPools.remove(poolName);
}
public static void main(String args[]) {
initializePool("vizidtoud");
}
}
I call the below testMethod, after putting it into a Callable(with other few Callable tasks), from an ExecutorService. I suspect that, the map.put() suffers OutOfMemoryError, as I'm trying to put some 20 million entries.
But, I'm not able to see the error trace in console. Just the thread stops still. I tried to catch the Error ( I know.. we shouldnt, but for debug I caught). But, the error is not caught. Directly enters finally and stops executing.. and the thread stands still.
private HashMap<String, Integer> testMethod(
String file ) {
try {
in = new FileInputStream(new File(file));
br = new BufferedReader(new InputStreamReader(in), 102400);
for (String line; (line= br.readLine()) != null;) {
map.put(line.substring(1,17),
Integer.parseInt(line.substring(18,20)));
}
System.out.println("Loop End"); // Not executed
} catch(Error e){
e.printStackTrace(); //Not executed
}finally {
System.out.println(map.size()); //Executed
br.close();
in.close();
}
return map;
}
Wt could be the mistake, I'm doing?
EDIT: This is how I execute the Thread.
Callable<Void> callable1 = new Callable<Void>() {
#Override
public Void call() throws Exception {
testMethod(inputFile);
return null;
}
};
Callable<Void> callable2 = new Callable<Void>() {
#Override
public Void call() throws Exception {
testMethod1();
return null;
}
};
List<Callable<Void>> taskList = new ArrayList<Callable<Void>>();
taskList.add(callable1);
taskList.add(callable2);
// create a pool executor with 3 threads
ExecutorService executor = Executors.newFixedThreadPool(3);
List<Future<Void>> future = executor.invokeAll(taskList);
//executor.invokeAll(taskList);
latch.await();
future.get(0);future.get(1); //Added this as per SubOptimal'sComment
But, this future.get() didn't show OOME in console.
You should not throw away the future after submitting the Callable.
Future future = pool.submit(callable);
future.get(); // this would show you the OOME
example based on the informations of the requestor to demonstrate
public static void main(String[] args) throws InterruptedException, ExecutionException {
Callable<Void> callableOOME = new Callable<Void>() {
#Override
public Void call() throws Exception {
System.out.println("callableOOME");
HashMap<String, Integer> map = new HashMap<>();
// some code to force an OOME
try {
for (int i = 0; i < 10_000_000; i++) {
map.put(Integer.toString(i), i);
}
} catch (Error e) {
e.printStackTrace();
} finally {
System.out.println("callableOOME: map size " + map.size());
}
return null;
}
};
Callable<Void> callableNormal = new Callable<Void>() {
#Override
public Void call() throws Exception {
System.out.println("callableNormal");
// some code to have a short "processing time"
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException ex) {
System.err.println(ex.getMessage());
}
return null;
}
};
List<Callable<Void>> taskList = new ArrayList<>();
taskList.add(callableOOME);
taskList.add(callableNormal);
ExecutorService executor = Executors.newFixedThreadPool(3);
List<Future<Void>> future = executor.invokeAll(taskList);
System.out.println("get future 0: ");
future.get(0).get();
System.out.println("get future 1: ");
future.get(1).get();
}
Try catching Throwable as it could be an Exception like IOException or NullPointerException, Throwable captures everything except System.exit();
Another possibility is that the thread doesn't die, instead it becomes increasingly slower and slower due to almost running out of memory but never giving up. You should be able to see this with a stack dump or using jvisualvm while it is running.
BTW Unless all you strings are exactly 16 characters long, you might like to call trim() on the to remove any padding in the String. This could make them shorter and use less memory.
I assume you are using a recent version of Java 7 or 8. If you are using Java 6 or older, it will use more memory as .substring() doesn't create a new underlying char[] to save CPU, but in this case wastes memory.
I have LinkedList Queue, and I'm trying to read a file with numbers of people in queue waiting to be helped and the number of agents available to help at the time. I do not know to check if they are busy or how to add the people waiting in the queue in the first place. Can anyone help me? This is the code I have so far.
public class WaitingQueue
{
public int [] windows = 0; // every time we add some one check if location occupied
public int time = 0;
public int waitTime = 0;
public static void main(String args[])
{
Queue newQueue = new Queue();
try{
FileInputStream fn = new FileInputStream(args[0]);
BufferedReader br = new BufferedReader(new InputStreamReader(fn));
String line;
while((line = br.readLine()) != null)
{
time++; // happens every time window i busy
waitTime++ // increment waiTime
if ( time for people to arrive)
{
add people to the queue // have to have a queue for people waiting.
//use enque to add people.
}
if(window is open)
{
// move people from queue to window
// use dequeue
}
if(time = x;)
{
// add some people to list
}
}
//Close the input stream
outFile.close();
fn.close();
}
}catch (Exception e)
{/*Catches exception*/
System.err.println("An error has occured : " + e.getMessage());
}
}
--EDIT--
I see your code has now been tagged in Java; my code is more of a c#/pseudo, so you might need to convert it into Java.
--EDIT--
Though this may not help. But I'd suggest a more entity orient approach; something like:
Agents, Agent List: Shall list the available agents
Customers, Customer Queue: Shall maintain a queue of customers wanting help
CustomerSupport Manager:
Shall see if an agent is available(not busy)
Dequeue the customer
Assign it to one of the available agents
Above the top of my head, see following:
Customer:
public class Customer
{
string _strName;
public Customer(string strName) { _strName = strName; }
}
Agent:
public class Agent
{
string _strName;
bool _bIsBusy = false;//
public bool IsBusy { get { return _bIsBusy; } }
Customer _Customer;
public Agent(string strName)
{
_strName = strName;
}
public void HandleCustomer(Customer theCustomer)
{
_Customer = theCustomer;
_bIsBusy = true;//Busy as long as the window is open.
//You might need something that doesnt block;
Thread.Sleep(5 * 1000); //Wait for time to simulate that agent is talking to customer
RemoveCustomer();//Done with the customer.
}
private void RemoveCustomer()
{
_Customer = null;
_bIsBusy = false;
}
}
Manager:
A class that manages the customers and agents, according to availability
public class CustomerServiceBench
{
Queue<Customer> queCustomers = new Queue<Customer>();
List<Agent> lstAgents = new List<Agent>();
Thread thdService;
public CustomerServiceBench()
{
//Something along these lines.
thdService = new Thread(delegate() { WaitAndAddCustomerIfAgentIsAvailable(); });
}
private void AddCustomer()
{
//Add a dummy customer.
Random r = new Random(1231);
queCustomers.Enqueue(new Customer("Customer" + r.Next().ToString()));
Thread.Sleep(5 * 1000); //SpinWait.Once()...
}
private void WaitAndAddCustomerIfAgentIsAvailable()
{
//Thread1 to manage the
}
}
It's not trivial so I suggest you search a bit for a tutorial with lots of example code and then alter it to suit your needs.
8.3 The Producer/Consumer Pattern - Java Threads, Third Edition
The producer-consumer pattern in Java 5: using blocking queues in preference to wait()/notify()