Java Chapter 9 learning experience

Keywords: Java Back-end

Write before:

This chapter mainly talks about the knowledge of threads. Thread is essentially different from other chapters. The reason is that thread allows you to do multiple things at the same time and execute some tasks concurrently. Then let's explore the important knowledge in this chapter.

catalog:

1. What is the function of futuretask class? What interfaces does it implement? What is the difference between the Callable interface and the Runnable interface?

2. What is the function of volatile keyword? Please give an example.

3. Write a Java program to simulate the optimal process of boiling water and making tea.

4. Write a producer / consumer Java application based on multithreading, generate 10 producer and consumer threads respectively, share a buffer queue (length is self-set), the producer thread puts the product into the buffer, and the consumer thread takes the product out of the buffer.

5. read the official account of "code farmer turn over" - "I am a thread".

1. What is the function of futuretask class? What interfaces does it implement? What is the difference between the Callable interface and the Runnable interface?

A: the details are as follows.

FutureTask represents an asynchronous calculation that can be canceled. FutureTask class provides a basic implementation of Future, with methods to start and cancel calculation, query whether the calculation is complete, and retrieve the calculation results. The results can only be retrieved after the calculation is completed; If the calculation has not been completed, the get method will block it. Once the calculation is complete, you cannot restart or cancel the calculation (unless the calculation is called using runAndReset()).

FutureTask implements the RunnableFuture interface, which inherits the RunnableFuture interface and the Future interface. Therefore, FutureTask has both Runnable and Future features

Let's talk about the Callable interface.

Interface Callable<V>   V call() throws Exception   It can return the calculated result value and throw an exception. Here, we see that the return value type of the function is V, and the parameters we pass in happen to be V, so an ideal result is achieved: what type of parameters I pass in, what type of parameters callable returns. If no parameters are passed, no parameters are returned.

Let's take an example:

class Adder implements Callable<Integer>
{   
    int[] datas=null;
    Adder(int[] _datas){
       datas = _datas;
    }
public Integer call(){
     int sum=0;
     for (int i=0;i<datas.length;i++){
         sum+=datas[i];
         System.out.println(sum);
     }
     return Integer.valueOf(sum); }}

Then we can get the sum of all the numbers in the integer array by using the call method of the Adder class object.

Another Runnable interface:

Interface abstract method: public void run(); You also need to override the run method.

public class MyThread {
    public static void main ( String args[] ) {                 
       Thread a = new Thread(new Runnable(){//Anonymous Inner Class 
          public void run(){
             System.out.println("This is another thread.");
          }
       });
       a.start();
       System.out.println("This is main thread."); 
    }                                             
}//In the above examples, the newly created MyThread class object is used only once. As mentioned earlier, anonymous class objects can be used to write.
public class MyThread {
    public static void main ( String args[] ) {                
        Thread a = new Thread(()->{
             System.out.println("This is another thread.");
        }); //Lambda abbreviation, Java SE8 feature     
        a.start();
        System.out.println("This is main thread.");  
   }                                             
}

  This method is more flexible, and multiple threads can share the resources of an object. (the same as the target value, they all point to the object being used)

The biggest difference between the two is that runnable does not return a value, while the task thread that implements the callback interface can return the execution result; The run method in the callable interface implementation class allows exceptions to be thrown upward, but exceptions in the run method implemented in the runnable interface must be handled internally rather than thrown upward.

2. What is the function of volatile keyword? Please give an example.

A: see below for details.

We know that in order to improve efficiency, when a variable needs to be used, it usually does not tend to read from the hard disk and memory, but from the cache. In this way, each code block can back up a copy of this variable for the next use. However, it is this efficient and convenient method that brings hidden dangers in threading.

For example, there are two threads that need to operate on the same variable I. if there is no restriction, they will cache the initial I and then operate separately. Suppose that these two threads should perform i-- operations alternately, but due to this cache problem, there is no way to ensure that they are executed strictly according to what you do once and me once. For example, as soon as the thread executes for the first time, the I backed up by the thread is reduced by 1; The next time thread 2 executes, thread 2's I minus 1. This minus one operation is executed twice, but no I is equal to 8

volatile solves this problem. Well, from now on, you don't use the cache for me. You'd rather be troublesome. Now i can be guaranteed to be equal to 8, but there is another problem, that is, this i cannot be guaranteed to be equal to 8 according to our assumption. As long as a thread executes twice continuously, we can get this result, but we hope to achieve two purposes: first, two threads execute alternately; Second, this i is subtracted by 1 from each of the two threads to get 8. The second task is half completed, and the most essential thing has not been solved: the alternating execution of threads cannot be guaranteed.

However, this step is still indispensable. To be exact, this is a necessary condition for completing the task, not a sufficient condition, and naturally not a sufficient and necessary condition.

3. Write a Java program to simulate the optimal process of boiling water and making tea.

A: the details are as follows.

import java.util.*;
import java.util.concurrent.*;
/**
 * FutureTask_1 Tasks to be performed: washing kettle, boiling water and making tea
 */
class FutureTask_1 implements Callable<String> {

    // FutureTask_ Futuretask held in 1_ 2 references
    FutureTask<String> futureTask_2;

    // Initializing member variables through constructors
    public FutureTask_1(FutureTask<String> futureTask_2) {
        this.futureTask_2 = futureTask_2;
    }

    // Override the call method in the Callable interface.
    @Override
    public String call() throws Exception {

        System.out.println("T1: Kettle");
        TimeUnit.SECONDS.sleep(1);

        System.out.println("T1: Boil water");
        TimeUnit.SECONDS.sleep(15);

        // Gets the name of the T2 thread
        String teas = futureTask_2.get();
        System.out.println("Get tea:" + teas);

        System.out.println("T1: Start making tea...");

        return "Serving tea:" + teas;
    }
}
/**
 * FutureTask_2 Tasks to be performed: washing teapots, cups and tea
 */
class FutureTask_2 implements Callable<String> {

    @Override
    public String call() throws Exception {

        System.out.println("T2: Wash the teapot");
        TimeUnit.SECONDS.sleep(1);

        System.out.println("T2: Wash the tea cup");
        TimeUnit.SECONDS.sleep(2);

        System.out.println("T2: Take tea");
        TimeUnit.SECONDS.sleep(1);

        return "Jasmine Tea";
    }
}
public class TEST{
    public static void main(String []args){

        // Create FutureTask_2 tasks
        FutureTask<String> futureTask_2 = new FutureTask<>(new FutureTask_2());
        // Create FutureTask_1, and FutureTask_2 task reference incoming
        FutureTask<String> futureTask_1 = new FutureTask<>(new FutureTask_1(futureTask_2));

        // Create thread T1 to execute the task futuretask_ one
        Thread t1 = new Thread(futureTask_1);
        t1.start();

        // Create thread T2 to execute the task futuretask_ two
        Thread t2 = new Thread(futureTask_2);
        t2.start();

        try {
            // Get task futuretask_ Result of the last step of 1
            System.out.println(futureTask_1.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

4. Write a producer / consumer Java application based on multithreading, generate 10 producer and consumer threads respectively, share a buffer queue (length is self-set), the producer thread puts the product into the buffer, and the consumer thread takes the product out of the buffer.

class Resource implements Runnable {
  volatile public int i;        
  volatile public Integer it;
  public  Resource(int _i){
    i = _i;
    it = new Integer(i);
  }
  public  void run(){
   while(true){
    synchronized(it){
     if (i>0){
        try{
           Thread.sleep(200);
        }
        catch(Exception e){}
        i--;
        System.out.println(Thread.
        currentThread().getName()+"  "+i);
    }
    else{
        System.out.println(Thread.
        currentThread().getName());
        break; }}
}}}
class Maker implements Runnable {
  volatile public int i;        
  volatile public Integer it;
  public  Maker(int _i){
    i = _i;
    it = new Integer(i);
  }
  public  void run(){
   while(true){
    synchronized(it){
     if (i>0){
        try{
           Thread.sleep(200);
        }
        catch(Exception e){}
        i++;
        System.out.println(Thread.
        currentThread().getName()+"  "+i);
    }
    else{
        System.out.println(Thread.
        currentThread().getName());
        break; }}
}}}
public class TestSecurity{
public static void main(String[] args){
  Resource m = new Resource(9);
  Thread t1 = new Thread(m);
  Thread t2 = new Thread(m);
  Maker m1=new Maker(m);
  Maker m2=new Maker(m);
  t1.start();
  t2.start();
  m1.start();
  m2.start();
}
}

5. read the official account of "code farmer turn over" - "I am a thread".

I really recommend you to have a look. It is simple and easy to understand. Many decisions and ideas are closer to the distribution and scheduling problem in real life, so that everyone can truly feel that this thing has indeed brought us a lot of convenience. In this way, we can better simulate more problems in life and make the code "smart", which greatly reduces our burden.

Well, that's it

I heard you haven't paid any attention?!

Hum! I'll count three. If I don't praise, collect and pay attention, I'll eat you!

Posted by akreation on Sun, 28 Nov 2021 21:34:21 -0800