class Program
{
static void Main(string[] args)
{
Thread thread1 = new Thread((ThreadStart)DLockSample.FunctionA);
Thread therad2 = new Thread((ThreadStart)DLockSample.FunctionB);
thread1.Start();
therad2.Start();
}
}
public class DLockSample
{
static object object1 = new object();
static object object2 = new object();
public static void FunctionA()
{
lock (object1)
{
Thread.Sleep(1000);
lock (object2)
{
Thread.Sleep(1000);
Console.WriteLine("heart beat - object2");
}
}
}
public static void FunctionB()
{
lock (object2)
{
lock (object1)
{
Thread.Sleep(1000);
Console.WriteLine("heart beat - object1");
}
}
} }
Always enter the locks in the same order in all threads. See also hierarchy of critical sections I.e. FunctionB needs to be:
public static void FunctionB()
{
lock (object1)
{
lock (object2)
...
That's a pretty abstact problem to fix. Just a few tips:
Always lock on objects in the same order
If it's impossible to lock in the same order, use object's fields to preserve the order (for example, if A.Id > B.Id then always lock on A before B).
Related
I have a use case where I have a set of items, DiagnosticRuns, that are submitted to my cluster. I want to process them serially (to avoid conflicts). I am trying to use a Hazelcast Queue protected by a Lock to make sure the items are processed one at a time. Hazelcast is running in embedded mode in my cluster. If I register an ItemListener with the Queue, is it safe to call take() on the Queue from within the itemAdded() method? For example:
#Component
public class DistributedQueueListener
{
public static final String DIAGNOSTICS_RUN_QUEUE_NAME = "diagnosticRun";
#Autowired
private HazelcastInstance hazelcast;
#Autowired
private ProductVersioningService productVersioningService;
private IQueue<DiagnosticRun> diagnosticRunQueue;
private ILock diagnosticRunLock;
private String diagnosticRunListenerId;
#PostConstruct
public void init()
{
diagnosticRunQueue = hazelcast.getQueue(DIAGNOSTICS_RUN_QUEUE_NAME);
diagnosticRunLock = hazelcast.getLock("diagnosticRunLock");
diagnosticRunListenerId = diagnosticRunQueue.addItemListener(new DiagnosticRunListener(), false);
}
#PreDestroy
public void stop()
{
diagnosticRunQueue.removeItemListener(diagnosticRunListenerId);
}
public class DiagnosticRunListener implements ItemListener<DiagnosticRun>
{
#Override
public void itemAdded(ItemEvent<diagnosticRun> item)
{
diagnosticRunLock.lock(5, TimeUnit.SECONDS);
try
{
DiagnosticRun diagnosticRun = diagnosticRunQueue.poll();
if(diagnosticRun != null)
{
productVersioningService.updateProductDeviceTable(diagnosticRun);
}
}
finally
{
diagnosticRunLock.unlock();
}
}
#Override
public void itemRemoved(ItemEvent<diagnosticRun> item)
{
}
}
}
I'm not sure whether it's threadsafe to call take() on the Queue from that location and thread.
If that is not allowed, I'll have to set up my own long-running loop to poll() the Queue. I'm not sure what's the best way to set up a long-running thread in a Spring Boot application. Assuming the method above does not work, would the below code be threadsafe? Or is there a better way to do this?
#Component
public class DistributedQueueListener
{
public static final String DIAGNOSTIC_RUN_QUEUE_NAME = "diagnosticRun";
#Autowired
private HazelcastInstance hazelcast;
#Autowired
private ProductVersioningService productVersioningService;
private IQueue<diagnosticRun> diagnosticRunQueue;
private ILock diagnosticRunLock;
private ExecutorService executorService;
#PostConstruct
public void init()
{
diagnosticRunQueue = hazelcast.getQueue(DIAGNOSTIC_RUN_QUEUE_NAME);
diagnosticRunLock = hazelcast.getLock("diagnosticRunLock");
executorService = Executors.newFixedThreadPool(1);
executorService.submit(() -> listenToDiagnosticRuns());
}
#PreDestroy
public void stop()
{
executorService.shutdown();
}
private void listenToDiagnosticRuns()
{
while(!executorService.isShutdown())
{
diagnosticRunLock.lock(5, TimeUnit.SECONDS);
try
{
DiagnosticRun diagnosticRun = diagnosticRunQueue.poll(1L, TimeUnit.SECONDS);
productVersioningService.updateProductDeviceTable(diagnosticRun);
}
catch(InterruptedException e)
{
logger.error("Interrupted polling diagnosticRun queue", e);
}
finally
{
diagnosticRunLock.unlock();
}
}
}
}
First I'll qualify that I'm not exactly an expert on which threads these are executed on and when so some may disagree but here're my thoughts on this so anyone please chime in as this looks to be an interesting case. Your first solution mixes the Hazelcast event threading with it's operation threading. In fact you're triggering three operations to be invoked as a result of the single event. If you put some arbitrary latency in your call to updateProcductDeviceTable, you'll see that eventually, it will slow down but resume up again after some time. This will cause your local event queue to pile up while operations are invoked. You could put everything you're doing in a separate thread which you can "wake" up on #itemAdded or if you can afford to have a bit of latency, do what you're doing on your second solution. I would, however, make a couple changes in
listenToDiagnosticsRuns() method:
private void listenToDiagnosticRuns()
{
while(!executorService.isShutdown())
{
if(diagnosticRunQueue.peek() != null)
{
diagnosticRunLock.lock(5, TimeUnit.SECONDS);
try
{
DiagnosticRun diagnosticRun = diagnosticRunQueue.poll(1L, TimeUnit.SECONDS);
if(diagnosticRun != null)
{
productVersioningService.updateProductDeviceTable(diagnosticRun);
}
}
catch(InterruptedException e)
{
logger.error("Interrupted polling diagnosticRun queue", e);
}
finally
{
diagnosticRunLock.unlock();
}
} // peek != null
else
{
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
//do nothing
}
}
}
}
public class SetGetFail implements Runnable {
// Every thread is assigned a number and has a reference to a SharedObject.
// In main(), a single SharedObject is passed to all threads.
int number;
SharedObject shared;
public SetGetFail(int no, SharedObject so) {
number = no;
shared = so;
}
public static void main(String[] args) {
SharedObject shared = new SharedObject(0);
new Thread(new SetGetFail(1, shared)).start();
new Thread(new SetGetFail(2, shared)).start();
}
synchronized public void run() {
setGet();
}
synchronized void setGet() {
// Repeatedly assign this thread's own number to the shared
// object and race to read that number again.
// Exit, if some other thread modified the number in between.
while(true) {
shared.setNo(number);
int no = shared.getNo();
if (no != number) {
System.out.println("Thread " + number + " sees " + no);
System.exit(no);
}
}
}}
So my question to the code is, why "synchronized" do not prevent races between these threads?
Thread 2 should be locked while Thread 1 is getting/setting the Value from shared, but the result is still "Thread 2 sees 1".
Change the code like this. I have added an additional log statement just to prove you that it is running. Now let me explain the issue. You have just declared the method that modifies the shared state as this.
synchronized void setGet() {
// ...
}
So each thread gets it's own lock and modify the shared data at the same time. That's why your thread-2 sees the value 1 which is set by the other thread. To guard this you need to use a lock which is common to both the thread1 and thread2 instances. For that you need to use an explicit lock object which is shared among both the threads and synchronize using that shared lock. So that's what I have done to solve the issue.
private static final Object lock = new Object();
synchronized (lock) {
// ...
}
public class SetGetFail implements Runnable {
// Every thread is assigned a number and has a reference to a SharedObject.
// In main(), a single SharedObject is passed to all threads.
int number;
SharedObject shared;
private static Object lock = new Object();
public SetGetFail(int no, SharedObject so) {
number = no;
shared = so;
}
public static void main(String[] args) throws InterruptedException {
SharedObject shared = new SharedObject(0);
new Thread(new SetGetFail(1, shared), "One").start();
new Thread(new SetGetFail(2, shared), "Two").start();
}
synchronized public void run() {
setGet();
}
void setGet() {
// Repeatedly assign this thread's own number to the shared
// object and race to read that number again.
// Exit, if some other thread modified the number in between.
while (true) {
synchronized (lock) {
shared.setNo(number);
int no = shared.getNo();
if (no != number) {
System.out.println("Thread " + number + " sees " + no);
System.exit(no);
}
System.out.println("Thread " + number + " sees " + no);
}
}
}
}
I interested in one interesting task. I have UI in JavaFx with another thread which updates UI. I started updates from Platform.runLater. Code:
private void startUpdateDaemon() {
updateUserStatus();
updateTable();
}
private void startUpdateDaemonTask() {
Task task = new Task<Void>() {
#Override
protected Void call() throws Exception {
while (true) {
Platform.runLater(() -> {
startUpdateDaemon();
});
Thread.sleep(1000);
}
}
};
Thread th = new Thread(task);
th.setDaemon(true);
th.start();
}
#Override
public void initialize(URL location, ResourceBundle resources) {
startUpdateDaemonTask();
}
Also I have place in another class where I updates UI:
private void startUpdateDaemonTask() {
Task task = new Task<Void>() {
#Override
protected Void call() throws Exception {
while (true) {
Platform.runLater(new Runnable() {
#Override
public void run() {
updateGameStatus();
}
});
Thread.sleep(1000);
}
}
};
Thread th = new Thread(task);
th.setDaemon(true);
th.start();
}
So, finally I have two places with call "Platform.runLater" and different methods inside.
My question is Can I create only "one" method with one time call "Platform.runLater" and send to this method different methods which will be call ?? May be I can write finish method with consumers and send to him methods 'startUpdateDaemon()' and 'updateGameStatus()'?
Thanks a lot.
You can add a Runnable parameter to your method. This parameter is given to you Platform.runLater:
private void startUpdateDaemonTask(Runnable runner) {
Task task = new Task<Void>() {
#Override
protected Void call() throws Exception {
while (true) {
Platform.runLater(runner);
Thread.sleep(1000);
}
}
};
Thread th = new Thread(task);
th.setDaemon(true);
th.start();
}
Now you can invoke this method with your method references:
startUpdateDaemonTask(this::startUpdateDaemon);
startUpdateDaemonTask(this::updateGameStatus);
I am trying to run a thread in background with while(true) condition, and not using any join after the thread so that it continue running the main thread. But what I am observing is only while loop is running and it is not switching to main thread. please help me find the issue. This is Groovy code.
public static void main(args) {
Thread.start {
while (true) {
long sleepMillis = 2000
System.out.println("inside async block")
Thread.sleep(sleepMillis)
}
}
//main func code goes here
}
Please give me pointers to the issue.
Here You go:
public class Lol {
public static void main(String[] args) {
def t = new Thread(new Runnable() {
public void run() {
while(true) {
println 'lol'
Thread.sleep(500)
}
}
}).start()
println 'other'
}
}
I have a thread like:
startButton.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field arg0, int arg1) {
Thread thread = new Thread(){
public void run() {
uploadFile();
}
};
thread.start();
}
//});
});
The uploadFile method contains the line label_up_result.setText(result); which causes an IllegalStateException.
label_up_result is defined like: final LabelField label_up_result=new LabelField("", LabelField.FIELD_LEFT);
What can be the problem ? How can I fix it ?
The problem is probably that you are trying to update the UI from a worker thread. There are two approaches. You can synchronize on the event lock:
synchronized(UiApplication.getUiApplication().getEventLock())) {
label_up_result.setText(result);
}
or you can create a Runnable to execute on the UI thread:
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
label_up_result.setText(result);
}
});
I don't know about blackberry, but usually you need to perform the ui-actions in the ui-thread. SwingUtilities.invokeLater provides that functionality in JavaSE, http://www.java2s.com/Code/Java/Swing-JFC/Swinginvokelater.htm