I'm a java engineer, and I'm trying to find a way to make calling of method in class thread-safe as the code snippet shows below:
class A:
def __init__(self, id):
self.x = X(id)
def switch(self, new_id):
self.x = X(new_id) # switch to another object
def log(self, msg):
self.x.log(msg)
a = A()
I'm wondering, if a
is being used by multi-thread, and sometimes switch
method is called, will log
method suffer from NullPointerException
where self.x could be None with chances?
Thanks!
CodePudding user response:
At no point in the program does self.x
get set to None
. If we take a look at the generated Python byte code for the switch
function, we see that self.x
is immediately replaced with the new X
instance without being set to None
:
# Create the new X instance
0 LOAD_GLOBAL 0 (X)
2 LOAD_FAST 1 (new_id)
4 CALL_FUNCTION 1
# Store the new self.x
6 LOAD_FAST 0 (self)
8 STORE_ATTR 1 (x)
# Return from the function
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
To double-check that there won't be any NullPointerException
-like error such as this:
AttributeError: 'NoneType' object has no attribute 'log'
I created a simple Python script that calls repeatedly the switch
and log
methods in two separate threads without acquiring any locks.
import threading
import random
class X:
def __init__(self, id) -> None:
self.id = id
def log(self, msg):
print(f'{self.id}: {msg}')
class A:
def __init__(self, id):
self.x = X(id)
def switch(self, new_id):
self.x = X(new_id) # switch to another object
def log(self, msg):
self.x.log(msg)
a = A(0)
def switch_t():
while True:
a.switch(random.randint(0, 100))
def log_t():
while True:
a.log(random.randint(0, 100))
t1 = threading.Thread(target=switch_t)
t2 = threading.Thread(target=log_t)
t1.start()
t2.start()
I ran this code for two minutes and it never threw any errors.
So, as long as you don't require self.x
to remain the same during the execution of log
, in case you wanted to access self.x
more than one time, your code is completely fine and you won't come across any NullPointerException
-like error.
One more thing to point out, in a = A()
, you forgot the constructor arguments.