ZooKeeper Distributed topics and introduction to Dubbo microservices
Zookeeper implements distributed locks
What multithreading
Multithreading In order to improve the running efficiency of application programs, there are multiple execution paths in a process, which are executed in parallel without affecting each other.
Here is not much about the introduction of threads, to learn more about threads please go to github.com/haoxiaoyong…
Below we only for distributed environment implementation of distributed lock introduction;
What is the Java Memory model
The shared Memory model refers to the Java Memory model (JMM), which determines that a shared variable written by one thread can be visible to another thread. From an abstract point of view, JMM defines an abstract relationship between threads and main memory: Shared variables between threads are stored in main memory, and each thread has a private local memory where it stores copies of shared variables to read/write. Local memory is an abstraction of the JMM and does not really exist. It covers caches, write buffers, registers, and other hardware and compiler optimizations
From the above figure, thread A and thread B must go through the following two steps in order to communicate:
-
First, thread A flusher the updated shared variables from local memory A to main memory.
-
Thread B then goes into main memory to read the shared variables that thread A has updated previously.
As shown in the figure above, local memory A and B have copies of the shared variable X in main memory. So let’s say that at the beginning, all three of these memory x values are 0. When thread A executes, it temporarily stores the updated x value (suppose 1) in its local memory, A. When thread A and thread B need to communicate, thread A will first refresh the modified X value in its local memory to the main memory, and the x value in the main memory becomes 1. Thread B then goes to main memory to read thread A’s updated x value, and thread B’s local memory x value also changes to 1. Taken as A whole, these two steps are essentially thread A sending messages to thread B, and this communication must go through main memory. The JMM provides memory visibility assurance for Java programs by controlling the interaction between main memory and the local memory of each thread.
Summary: What is the Java Memory Model? The Java Memory Model, or JMM, defines the visibility of one thread to another. Shared variables are stored in main memory, and each thread has its own local memory. When multiple threads access the same data at the same time, local memory may not be flushed to main memory in time, so thread-safety issues can occur.
Traditionally, order ID is generated
Generate order class
public class OrderNumGenerator {
// Global order id;
public static int count = 0;
public String getNumber(a) {
try {
//TimeUnit.SECONDS.sleep(2);
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
SimpleDateFormat simpt = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
return simpt.format(new Date()) + "-"+ ++count; }}Copy the code
Order number generation using multithreading simulation
public class OrderService implements Runnable {
private OrderNumGenerator orderNumGenerator = new OrderNumGenerator();
public void run(a) {
getNumber();
}
public void getNumber(a) {
String number = orderNumGenerator.getNumber();
System.out.println(Thread.currentThread().getName() + ", generate order ID: + number);
}
public static void main(String[] args) {
System.out.println("#### generates unique order number ###");
for (int i = 0; i < 100; i++) {
new Thread(newOrderService()).start(); }}}Copy the code
This is where thread safety comes in;
There are many ways to solve this thread safety problem
For example, use synchronized or lock
Synchronized is omitted here. To learn more about the semantics and use of synchronized, go to github.com/haoxiaoyong…
Using lock locks to solve thread safety problems:
Generate order class
public class OrderNumGenerator {
// Global order id;
public static int count = 0;
public String getNumber(a) {
try {
//TimeUnit.SECONDS.sleep(2);
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
SimpleDateFormat simpt = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
return simpt.format(new Date()) + "-"+ ++count; }}Copy the code
No changes have been made;
Using multithreading simulation to generate order numbers (lock):
public class OrderService implements Runnable {
private OrderNumGenerator orderNumGenerator = new OrderNumGenerator();
// Use lock to lock
private java.util.concurrent.locks.Lock lock = new ReentrantLock();
public void run(a) {
getNumber();
}
public void getNumber(a) {
try {
lock.lock();
String number = orderNumGenerator.getNumber();
System.out.println(Thread.currentThread().getName() + ", generate order ID: + number);
} catch (Exception e) {
e.printStackTrace();
} finally{ lock.unlock(); }}public static void main(String[] args) {
System.out.println("#### generates unique order number ###");
OrderService orderService = new OrderService();
for (int i = 0; i < 100; i++) {
newThread(orderService).start(); }}}Copy the code
Compare and contrast with before and those changes?
lock.lock(); Locked,
lock.unlock(); Release the lock
Also notice the OrderService object in the main method; It’s only instantiated once;
It prints perfectly to 100;
The following describes generating order ids in a distributed environment;
In a distributed (clustered) environment, synchronization cannot be achieved for each JVM, and the use of timestamps to generate order numbers in distributed scenarios may be repeated
Use distributed lock generation order number technology
1. Disadvantages of using a database to implement distributed locks: Poor performance and deadlocks are easy to occur when threads are abnormal 2. Using Redis to realize distributed lock disadvantages: lock failure time is difficult to control, prone to deadlock, non-blocking, non-reentrant 3. Zookeeper distributed lock implementation is relatively simple, reliable, using temporary nodes, easy to control the failure time
What is distributed locking
Distributed locks are generally used in distributed systems or multiple applications to control whether the same task is executed or the task execution sequence. In the project, multiple Tomcat applications are deployed, and the same task may be executed several times during scheduled task execution. We can use distributed locking to ensure that only one Tomcat application executes scheduled task at the same time
Use Zookeeper to implement distributed locks
Zookeeper implements distributed locking
Using zookeeper node to implement distributed lock, create a temporary sequence is suitable for the sequential program, general idea is to create a temporary sequence nodes, find out the minimum sequence nodes, access to distributed lock, disappear after completion of the program execution sequence nodes, through the watch to monitor the change of the nodes, find the smallest sequence from the rest of the node, Obtain distributed locks, perform corresponding processing, and so on…
Add the dependent
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
Copy the code
Create Lock interface
public interface Lock {
// Get the lock resource
void getLock(a);
/ / releases the lock
void unLock(a);
}
Copy the code
Create the ZookeeperAbstractLock abstract class
public abstract class ZookeeperAbstractLock implements Lock {
// zk connection address
private static final String CONNECTSTRING = "127.0.0.1:2181";
// Create a ZK connection
protected ZkClient zkClient = new ZkClient(CONNECTSTRING);
protected static final String PATH = "/lock";
public void getLock(a){
if(tryLock()){
System.out.println("## Get lock resources ####");
}else {
/ / wait for
waitLock();
// Retrieve the resourcegetLock(); }}// Get the lock resource
abstract boolean tryLock(a);
/ / wait for
abstract void waitLock(a);
public void unLock(a) {
if(zkClient ! =null) {
zkClient.close();
System.out.println("Release lock resources..."); }}}Copy the code
ZookeeperDistrbuteLock class
public class ZookeeperDistrbuteLock extends ZookeeperAbstractLock {
private CountDownLatch countDownLatch = null;
boolean tryLock(a) {
try {
zkClient.createEphemeral(PATH);
return true;
} catch (Exception e) {
// e.printStackTrace();
return false; }}void waitLock(a) {
IZkDataListener izkDataListener = new IZkDataListener() {
public void handleDataDeleted(String path) throws Exception {
// Wake up the waiting thread
if(countDownLatch ! =null) { countDownLatch.countDown(); }}public void handleDataChange(String path, Object data) throws Exception {}};// Register events
zkClient.subscribeDataChanges(PATH, izkDataListener);
if (zkClient.exists(PATH)) {
countDownLatch = new CountDownLatch(1);
try {
countDownLatch.await();
} catch(Exception e) { e.printStackTrace(); }}// Delete the listenerzkClient.unsubscribeDataChanges(PATH, izkDataListener); }}Copy the code
Run the Zookeeper lock
public class OrderService implements Runnable {
private OrderNumGenerator orderNumGenerator = new OrderNumGenerator();
// Use lock to lock
// private java.util.concurrent.locks.Lock lock = new ReentrantLock();
private Lock lock = new ZookeeperDistrbuteLock();
public void run(a) {
getNumber();
}
public void getNumber(a) {
try {
lock.getLock();
String number = orderNumGenerator.getNumber();
System.out.println(Thread.currentThread().getName() + ", generate order ID: + number);
} catch (Exception e) {
e.printStackTrace();
} finally{ lock.unLock(); }}public static void main(String[] args) {
System.out.println("#### generates unique order number ###");
// OrderService orderService = new OrderService();
for (int i = 0; i < 100; i++) {
new Thread( newOrderService()).start(); }}}Copy the code
Execute the main method:
## Get lock lock resources ####2019-08-19-22-32-50-1 Create order ID:2019-08-19-22-32-50-1 Create order ID:2019-08-19-22-32-50-1 Create order ID:2019-08-19-22-32-50-1 Create order ID...## Get lock lock resources ####2019-08-19-22-32-59-2...## Get lock lock resources ####Order ID:2019-08-19-22-33-08-3 Release lock resources...## Get lock lock resources ####2019-08-19-22-33-17-4...## Get lock lock resources ####2019-08-19-22-33-26-5 Order ID:2019-08-19-22-33-26-5## Get lock lock resources ####2019-08-19-22-33-35-6 Release lock resources...## Get lock lock resources ####2019-08-19-22-33-44-7 Release the lock resource...## Get lock lock resources ####2019-08-19-22-33-53-8...## Get lock lock resources ####Thread-17, 34-02-9 :2019-08-19-22-34-02-9## Get lock lock resources ####2019-08-19-22-11-10 ThREAD-19, 34-34-11-10## Get lock lock resources ####...Copy the code