JAVA writes a multi-threaded locked library book return and borrowing process

Article Directory

foreword

Learning Java with my tutor, I accidentally discovered the syntax and semantics of java multi-process and multi-threading today, to make a multi-threaded library process applet with locks

1 The concept of multi-process and multi-thread

        1.1 Multi-process

        A process is an execution activity of a program on a computer. When you run a program, you start a process. All processes used to complete various functions of the operating system are system processes, and all processes not started by the system are user processes.

        The memory of process A and process B is independent and not shared. For example, Warcraft game is a process, and NetEase Cloud Music is a process.
These two processes are independent and do not share resources.

        1.2 Multithreading

        A process consists of one or more threads. The thread is the actual running unit in the process, and it is a subtask that runs independently in the process. It is the smallest unit for operation scheduling by the operating system. It can be understood that a thread is the smallest unit of operation in a process.

        The relationship between processes and threads: a process contains N threads.

        For example: when playing League of Legends, many threads are started when the client is opened: queuing queue thread, friend chat thread, and payment thread. Under the League of Legends process, N threads are started.

2.Runnable task class and Thread thread class

        Just now we know that thread is the smallest unit of operation scheduling, and in Java, the Thread class is the thread class, its function is to mobilize the instance object of the Runnable class, and the task is the object. In order to create a task, you must first define a class that implements the Runnable interface for the task. The Runnable interface is very simple, it only contains a run method. This method needs to be implemented to tell the system how the thread will behave. As shown in the picture:

         Once a PrintString is defined, its constructor can be used to create a task. For example

Runnable printgreet = new PrintString("你好啊",50);

        Tasks must be executed in threads. The Thread class includes constructors for creating threads and methods for controlling threads. Use the following statement to create a task thread: call the start( method to tell the Java virtual machine that the thread is ready to run, as shown below, and print the incoming string 50 times:

Thread thread = new Thread(printsee);
thread.start();

        

        Note: Each thread can be in one of 5 states: New, Ready, Blocked, Running, Ended

3. Thread pool

        Thread starting a new thread for each task may limit throughput and cause performance degradation. The number of concurrent execution tasks can be managed through the thread pool. Java provides the Executor interface to execute tasks in the thread pool, and the ExecutorService interface to manage and control tasks.

         When using the thread pool to run the task object, you can specify the number of threads to run, and you can close the thread pool after running:

ExecutorService executor = Executors.newFixedThreadPool(2);  //指定线程池数量
executor.execute(new returnTask());     //添加线程
executor.execute(new boorroTask());     // 添加线程

//将线程池结束掉,释放资源
executor.shutdown();

4. Thread synchronization

        4.1 Asynchronous programming and synchronous programming

        Asynchronous programming model : thread t1 and thread t2 each execute their own tasks, t1 does not care about t2, t2 does not care about t1, and no one needs to wait for anyone. Asynchrony is concurrency.

        So when will data have security issues in a multi-threaded concurrent environment?

Three conditions are met:

  1. Condition 1: Multi-threaded concurrency.

  2. Condition 2: There is shared data.

  3. Condition 3: Shared data has modified behavior.

For example, the money saving program uses the thread pool to create 1000 money saving threads. The logic is as follows: run all the money saving threads directly. The code of the thread is to get the balance on the account, and then add 1 to the balance, but all threads run concurrently at the same time, resulting in Everyone reads the initial value of the balance at the same time and adds 1. After the thread pool ends, it is found that the balance is 2, which is equivalent to running only once, and task 2 overwrites the result of task 1. Task 1 and Task 2 access a common resource in a way that causes a conflict, known as a race condition. If an object of a class does not cause a race condition in a multi-line program, such a class is called thread-safe ((thread-safe). So the Account class in the figure is not thread-safe.

public class AccountWithoutSync {
  private static Account account = new Account();

  public static void main(String[] args) {
    ExecutorService executor = Executors.newCachedThreadPool();

    // 创建100个存钱线程
    for (int i = 0; i < 100; i++) {
      executor.execute(new AddAPennyTask());
    }
    executor.shutdown();
    // 等待线程完成
    while (!executor.isTerminated()) {
    }

    System.out.println("现在余额: " + account.getBalance());
  }

  // 建一个存钱任务类,调用存钱类Account,每次放1块钱
  private static class AddAPennyTask implements Runnable {
    public void run() {
      account.deposit(1);
    }
  }

  // 存钱类Account,每次放1块钱
  private static class Account {
    private int balance = 0;

    public int getBalance() {
      return balance;
    }

    public void deposit(int amount) {
      int newBalance = balance + amount;

      try {
        Thread.sleep(5);
      }
      catch (InterruptedException ex) {
      }

      balance = newBalance;
    }
  }
}

5. Explicit synchronization lock

        There are several methods in java, but I use an explicit synchronization lock. The method of use is: first create a lock, then set the unlocking conditions, lock it first when the business class runs one of the synchronization methods, and unlock it after running , other synchronization methods cannot be operated during this period, and the specific details will be added later, so let’s get a general understanding of this first.

private static Lock lock = new ReentrantLock();   //创建一把锁

private static Condition newDeposit = lock.newCondition();  //创建解锁条件

6. Complete code

public class TestThread {
    private static library library = new library();
    public static void main(String[] args) {
        System.out.println("-------------------");
        System.out.println("| 图书馆借书还书流程  |");
        System.out.println("-------------------");
        //新建线程池,把还书任务和借书任务放进去
        ExecutorService executor = Executors.newFixedThreadPool(2);
        executor.execute(new returnTask());
        executor.execute(new boorroTask());

        //将线程池结束掉,释放资源
        executor.shutdown();
    }

    //新建任务类returnTask,此任务的run方法可执行静态类图书馆的还书方法,每次随机还1-5本书,运行100次
    public static class returnTask implements Runnable{
        @Override
        public void run() {
            int j = 0;
            try{
                do {
                    library.returnBook((int)(Math.random()*5)+1);  //每次随机还书1-5本
                    Thread.sleep(1000);  //每次还书休眠1秒钟再继续
                    j++;
                    //限定每天只有一百人来借书或者还书
                }
                while(j<100);
            }
            catch(InterruptedException ex){
                ex.printStackTrace(); //有线程阻塞异常时不会中断程序
            }
        }
    }

    //新建任务类boorroTask,此任务的run方法可执行静态类图书馆的借书方法,每次随机借1-5本书,运行100次
    public static class boorroTask implements Runnable{
        public void run(){
            int i=0;
            try {
                do {
                    library.borrowBooks((int)(Math.random()*5)+1);
                    Thread.sleep(1000);   //每次借完书休眠1秒钟
                   i++;
                    //限定每天只有一百人来借书或者还书
                }
                while (i<100);
            }
            catch(InterruptedException ex){
                ex.printStackTrace(); //有线程阻塞异常时不会中断程序
            }
        }
    }

    //定义静态类:图书馆类library,里面有变量margin表示书籍余量,一个借书方法,一个还书方法
    public static class library{
        private static Lock lock = new ReentrantLock();   //创建一把锁

        private static Condition newDeposit = lock.newCondition();  //创建解锁条件

        private int margin; //书籍余量

        public int getMargin() {
            return margin;
        } //获取书籍余量

        //定义borrowBooks方法,此方法用于借书
        public void borrowBooks(int num){
            lock.lock(); //先上一把锁,防止同时借书的事情发生

            try {
                while (margin < num) {       //如果书籍余量小于要借书的余量就执行下面代码
                    System.out.println();
                    System.out.println("                                                                ");
                    System.out.println("\t\t\t 什么?你想要借"+num+"本!!!");   //打印出来,表示无能为力,先睡会觉先
                    System.out.println("\t\t\t\t\t\t没有这么多书,先等一会吧~");
                    System.out.println("                                                                ");
                    System.out.println();
                    newDeposit.await();      //把当前线程阻塞掉,不借那么快了
                }
                margin -= num; //如果余量大于要借测书,就把书借出去,余量减去借书数量
                System.out.println();
                System.out.println("****************************************************************");
                System.out.println("\t\t\t 借走了"+num+"本书"+"\t\t\t 还剩下"
                +margin+"本书");
                System.out.println("****************************************************************");
                System.out.println();

                }
            catch (InterruptedException ex){
                ex.printStackTrace();    //有线程阻塞异常时不会中断程序
            }
            finally {
                lock.unlock();  //无论有没有借书成功,都把锁打开
            }
        }

        //定义returnBook方法,此方法用于还书
        public void returnBook(int num){
            lock.lock();   //还书前先上锁
            try {
                margin += num; //书籍余量加上还书数量
                System.out.println();
                System.out.println("----------------------------------------------------------------");
                System.out.println("还书成功,数量为:"+num+"\t\t\t 当前书籍余量为:"
                +margin);
                System.out.println("----------------------------------------------------------------");
                System.out.println();
                newDeposit.signalAll();   //叫醒所有睡觉的借书进程,我还了几本书,你们可以借书了没,不够就继续碎觉吧
            }
            finally {
                lock.unlock();   //无论结果如何,开锁
            }
        }
    }
}

summary

         I will write here first today, and I will sort it out and send it out later when I have time.

        The road to Java is long, although the road is long and difficult, but the journey will come!

Guess you like

Origin blog.csdn.net/qq_51294997/article/details/130918696