A senior programmer has to understand concurrency

So far, you've learned all sequential programming, the concept of sequential programming is only one task at a time execution, sequential programming course, can solve many problems, but for a certain task, if we can perform concurrent program important part of it is important, but also can greatly improve the efficiency of the program, enjoy the convenience of concurrent bring you. However, proficiency in concurrent programming theory and technology, will CRUD for you is a kind of object-oriented and you just learn the same kind of leap.

As you can see, when the parallel tasks interfere with each other, the actual concurrency problem will ensue. And concurrency problem is not difficult to reproduce, you tend to ignore them in the actual testing process, because failure is seldom happen, which is why we need to study their conditions: If you ignore the problem of concurrency, you will eventually bear it to bring you harm.

Concurrent multi-faceted

Faster execution

Speed ​​problem sounds simple, if you want a program to run faster, so it can be cut into slices, each slice is running on a separate processor: the premise that these tasks are not each other contact.

Note: To improve the speed of the processor in the form of multi-core chip instead of appearing.

If you have a multiprocessor machine, then you can distribute multiple tasks among the processors, which greatly improves throughput. However, complicated procedures are generally improved performance on a single processor. Performance overhead on a single processing overhead on the performance of many large multi-processor, which increases than as 线程切换an important basis for (switching from one thread to another thread). On the surface, all parts of a program as a single task seems to run a little smaller cost, saving time thread switching.

Improved design code

The use of multi-tasking on a single CPU machine program at any time is still only in the implementation of a job, you console output to the naked eye like these threads work at the same time, this is nothing but a cover-up fills CPU, CPU for each task It provides no fixed time slices. Java threading mechanism is preemptive, which means that you have to write some kind of concession statement will allow the thread to switch, switch to the other thread.

The basic thread mechanism

Concurrent programming so that our program can be divided into a number of separate, independent tasks running. By using multi-threading mechanism, these independent tasks by each task 执行线程to drive. A thread is a single sequential process control flow. Thus, a single process can have concurrent execution of multiple tasks, but your program look each task has its own CPU the same. Segmentation is the underlying CPU time, usually you do not need to consider it.

Custom Task

Threads can drive tasks, so you need a way to describe the task, which can be made Runnableto provide an interface, in order to define the task, just implement Runnable and runachieve your logic to process.

public class TestThread implements Runnable{

    public static int i = 0;

    @Override
    public void run() {
        System.out.println("start thread..." + i);
        i++;
        System.out.println("end thread ..." + i);
    }

    public static void main(String[] args) {
        for(int i = 0;i < 5;i++){
            TestThread testThread = new TestThread();
            testThread.run();
        }
    }
}

Task run method will have some form of recycling, making the task run forever until no longer needed, so the method of setting run out of condition (there is an option to return directly from the run in, we will discuss below.)

In the run using static methods Thread.yield()you can use thread scheduling, it means suggestion thread mechanism to switch: You've done an important part of the implementation, and the rest to other threads to run a run. Note that implementation of the recommendations, rather than enforcement. Add Thread.yield below () you will see interesting output

public void run() {
  System.out.println("start thread..." + i);
  i++;
  Thread.yield();
  System.out.println("end thread ..." + i);
}

Thread class

The traditional way Runnable transform the way is to use the Thread class hosting him, is shown below using the Thread class to implement a thread.

public static void main(String[] args) {
  for(int i = 0;i < 5;i++){
    Thread t = new Thread(new TestThread());
    t.start();
  }
  System.out.println("Waiting thread ...");
}

Thread constructor requires only one Runnable object, call the object's start Thread () method for the thread to perform the necessary initialization, and then call the Runnable's run method to start a task in this thread. It can be seen before the run method is not over yet, run it was returned. In other words, the program will not run until the method is finished it will execute the following command.

Print out the name of each thread in the run method, it is better to see the different switching and scheduling of threads

@Override
public void run() {
  System.out.println(Thread.currentThread() + "start thread..." + i);
  i++;
  System.out.println(Thread.currentThread() + "end thread ..." + i);
}

This thread switching and scheduling is handed over 线程调度器to automatic control, if there are multiple processors on your machine, thread scheduler will quietly distribute the threads among the processors. Every operating results are not the same, because the thread scheduling mechanism is undetermined.

Use Executor

CachedThreadPool

JDK1.5 the java.util.concurrent package executor Executor will you manage the Thread object, which simplifies concurrent programming. Executor between client tasks and provides a level of indirection; client directly perform a different task, the task will be executed as intermediate objects. Executor allows you to manage asynchronous tasks to perform, without having to show the life cycle management of threads.

public static void main(String[] args) {
  ExecutorService service = Executors.newCachedThreadPool();
  for(int i = 0;i < 5;i++){
    service.execute(new TestThread());
  }
  service.shutdown();
}

We use the Executor to replace the display to create a Thread object. CachedThreadPoolCreates a thread for each task. Note: ExecutorService the object is to use the static Executorscreated, this method can determine the type of Executor. On shutDowncall can prevent a new task presented to ExecutorService, this thread exits after the completion of all tasks in the Executor.

FixedThreadPool

FixedThreadPool allows you to use a limited set of threads to start multithreading

public static void main(String[] args) {
  ExecutorService service = Executors.newFixedThreadPool(5);
  for(int i = 0;i < 5;i++){
    service.execute(new TestThread());
  }
  service.shutdown();
}

With FixedThreadPool you can make a one-time pre-execution high thread allocation and, therefore, can limit the number of threads. This saves time, because you do not have to pay each task a fixed overhead of creating a thread.

SingleThreadExecutor

SingleThreadExecutor is the number of threads to FixedThreadPool 1, and if you submit more than one-time tasks to SingleThreadPool, these tasks will line up, each mission will end before the start of the next task, all tasks will use the same thread. SingleThreadPool will serialize all submitted to his task, and will maintain its own (hidden) suspension queue.

public static void main(String[] args) {
  ExecutorService service = Executors.newSingleThreadExecutor();
  for(int i = 0;i < 5;i++){
    service.execute(new TestThread());
  }
  service.shutdown();
}

You can see from the results output, the task is next to perform. I was assigned the task of five threads, but these five thread is not like we saw earlier have to be swapped out the effect it every time off until his execution that thread, then the remaining threads continue to "take "execution path of this thread. You can use SingleThreadExecutor to ensure that any moment there is only one task running.

The return value is generated from the task

Runnable is an independent implementation of the tasks, but it does not return any value. If you want the task to return a value upon completion, this time you need to consider using Callablethe interface, which was introduced after JDK1.5, by calling its submitmethod, its return value can be placed on a Future object, and then () method returns the value after obtaining submitted according to the corresponding get.

public class TaskWithResult implements Callable<String> {

    private int id;

    public TaskWithResult(int id){
        this.id = id;
    }

    @Override
    public String call() throws Exception {
        return "result of TaskWithResult " + id;
    }
}

public class CallableDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executors = Executors.newCachedThreadPool();
        ArrayList<Future<String>> future = new ArrayList<>();
        for(int i = 0;i < 10;i++){

            // 返回的是调用 call 方法的结果
            future.add(executors.submit(new TaskWithResult(i)));
        }
        for(Future<String> fs : future){
            System.out.println(fs.get());
        }
    }
}

submit () method returns an object Future, Future object store is the result of your return. You can also use isDoneto query whether the Future has been completed.

Dormancy

A simple way to influence the behavior of the task is to make the thread sleep, given the selected sleep time, call its sleep()methods, generally used TimeUnitto replace the time class Thread.sleep()methods, examples are as follows:

public class SuperclassThread extends TestThread{

    @Override
    public void run() {
        System.out.println(Thread.currentThread() + "starting ..." );

        try {
            for(int i = 0;i < 5;i++){
                if(i == 3){
                    System.out.println(Thread.currentThread() + "sleeping ...");
                    TimeUnit.MILLISECONDS.sleep(1000);
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread() + "wakeup and end ...");
    }

    public static void main(String[] args) {
        ExecutorService executors = Executors.newCachedThreadPool();
        for(int i = 0;i < 5;i++){
            executors.execute(new SuperclassThread());
        }
        executors.shutdown();
    }
}

Comparison of methods on TimeUnit in sleep () method and Thread.sleep (), please refer to the following this blog

(https://www.cnblogs.com/xiadongqing/p/9925567.html)

priority

The above-mentioned thread scheduler for each thread of execution is unpredictable, then there is no way to tell random execution thread scheduler which is a priority task want to enforce it? You can set the thread priority status, telling the thread scheduler which thread execution priority is relatively high, "Please give the rider immediately send a single" thread scheduler inclined to allow the higher priority thread execution priority, however, this does not mean low-priority thread can not be executed, that is, the priority will not result in deadlocks. Lower priority threads just executed a lower frequency.

public class SimplePriorities implements Runnable{

    private int priority;

    public SimplePriorities(int priority) {
        this.priority = priority;
    }

    @Override
    public void run() {
        Thread.currentThread().setPriority(priority);
        for(int i = 0;i < 100;i++){
            System.out.println(this);
            if(i % 10 == 0){
                Thread.yield();
            }
        }
    }

    @Override
    public String toString() {
        return Thread.currentThread() + " " + priority;
    }

    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        for(int i = 0;i < 5;i++){
            service.execute(new SimplePriorities(Thread.MAX_PRIORITY));
        }
        service.execute(new SimplePriorities(Thread.MIN_PRIORITY));
    }
}

toString () method is covered, so by using a Thread.toString()printing method name of the thread. You can override the default output thread, there is employed Thread [pool-1-thread- 1,10, main] this form of output.

By output, you can see, the last one the lowest priority thread of the rest of the thread with the highest priority. Note that the priority is set at the beginning of the run, set in the constructor they are not any good, because this time the thread has not executed tasks.

Although there are 10 priority JDK, but generally only MAX_PRIORITY, NORM_PRIORITY, MIN_PRIORITY three levels.

make compromise

We mentioned above, if you know a thread already in the run () method to run almost, then it may be a hint to the thread scheduler: I have completed the task in the most important part, may give other threads the CPU. This hint will be made by the yield () method.

There is a very important point is, Thread.yield () is recommended to perform a handover CPU, rather than enforcing CPU switch.

For any significant control or when calling application, can not rely on the yield()method, in fact, yield () method is often abused.

Background thread

Background (daemon) thread, the thread refers to a service running in the background provided, this thread is not necessary to belong to. At the end of all non-background threads, the program will stop, and it will terminate all background thread. Conversely, as long as there is any non-background threads still running, the program will not be terminated.

public class SimpleDaemons implements Runnable{

    @Override
    public void run() {
        while (true){
            try {
                TimeUnit.MILLISECONDS.sleep(100);
                System.out.println(Thread.currentThread() + " " + this);
            } catch (InterruptedException e) {
                System.out.println("sleep() interrupted");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        for(int i = 0;i < 10;i++){
            Thread daemon = new Thread(new SimpleDaemons());
            daemon.setDaemon(true);
            daemon.start();
        }
        System.out.println("All Daemons started");
        TimeUnit.MILLISECONDS.sleep(175);
    }
}

It will be created in each cycle 10 threads, and each thread is set to the background thread, and then began to run, for circulation will be ten times, and then output the information, then stop running after the main thread to sleep for a while. In each run cycle, it will print information about the current thread, the main thread has finished running, the program execution is completed. Because daemona background thread, can not affect the execution of the main thread.

But when you take daemon.setDaemon(true)the time to remove, while (true) will be infinite loop, it has been the main thread to perform the most important task, it would have been unable to stop the cycle continues.

ThreadFactory

Needed to create objects thread. Alternatively the thread factory using hardwired or Thread Runnable interface, allows the program to use the special thread subclass and priority. Create a general way

class SimpleThreadFactory implements ThreadFactory {
  public Thread newThread(Runnable r) {
    return new Thread(r);
  }
}

Executors.defaultThreadFactory provides a simple method to achieve a more useful thread context set it before returning to a known value will be created

ThreadFactory is an interface that only one way is to create a thread method

public interface ThreadFactory {

    // 构建一个新的线程。实现类可能初始化优先级,名称,后台线程状态和 线程组等
    Thread newThread(Runnable r);
}

Let's look at a case ThreadFactory

public class DaemonThreadFactory implements ThreadFactory {

    @Override
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }
}

public class DaemonFromFactory implements Runnable{

    @Override
    public void run() {
        while (true){
            try {
                TimeUnit.MILLISECONDS.sleep(100);
                System.out.println(Thread.currentThread() + " " + this);
            } catch (InterruptedException e) {
                System.out.println("Interrupted");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ExecutorService service = Executors.newCachedThreadPool(new DaemonThreadFactory());
        for(int i = 0;i < 10;i++){
            service.execute(new DaemonFromFactory());
        }
        System.out.println("All daemons started");
        TimeUnit.MILLISECONDS.sleep(500);
    }
}

Executors.newCachedThreadPool We can accept a thread pool object, creating a thread pool that creates new threads as needed, but will be available to reuse previously constructed threads in them, and if necessary use the ThreadFactory to create a new thread.

public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
  return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                60L, TimeUnit.SECONDS,
                                new SynchronousQueue<Runnable>(),
                                threadFactory);
}

Join a thread

A thread can call on other threads join()method, the effect is to wait for some time until the end of the second thread to perform the normal. If a thread calls t.join () method on another thread t, this thread will be suspended until the end of the target thread t only reply (you can use t.isAlive () returns true or false judgment).

Can also bring join when calling a timeout parameter, to set an expiration time, the expiration time, the method automatically returns join.

Call to join can also be interrupted practice to call on the thread interruptedmethod, then you need to use try ... catch clause

public class TestJoinMethod extends Thread{

    @Override
    public void run() {
        for(int i = 0;i < 5;i++){
            try {
                TimeUnit.MILLISECONDS.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println("Interrupted sleep");
            }
            System.out.println(Thread.currentThread() + " " + i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TestJoinMethod join1 = new TestJoinMethod();
        TestJoinMethod join2 = new TestJoinMethod();
        TestJoinMethod join3 = new TestJoinMethod();

        join1.start();
//        join1.join();

        join2.start();
        join3.start();
    }
}

join () method waits thread to die. In other words, it causes the currently running thread to stop execution until it joins the thread to complete its task.

Thread exception caught

Due to the nature of the thread, the thread that you can not escape from capture anomalies, abnormal escaped once run method task, it will spread out to the console, unless you take special steps to catch this error exception, in Java5 before you can capture the group by a thread, but after Java5, you need to use Executor to solve the problem, because the thread group is not a good attempt.

The following tasks will be thrown during the execution of the run method is an exception, and this exception will be thrown out of the run method, and the main method can not capture it

public class ExceptionThread implements Runnable{

    @Override
    public void run() {
        throw new RuntimeException();
    }

    public static void main(String[] args) {
        try {
            ExecutorService service = Executors.newCachedThreadPool();
            service.execute(new ExceptionThread());
        }catch (Exception e){
            System.out.println("eeeee");
        }
    }
}

To solve this problem, we need to modify the Executor spawns a thread way, Java5 provides a new interface Thread.UncaughtExceptionHandlerthat allows you attach an exception handler on each Thread. Thread.UncaughtExceptionHandler.uncaughtException()When near death due to uncaught is called a thread.

public class ExceptionThread2 implements Runnable{

    @Override
    public void run() {
        Thread t = Thread.currentThread();
        System.out.println("run() by " + t);
        System.out.println("eh = " + t.getUncaughtExceptionHandler());
      
        // 手动抛出异常
        throw new RuntimeException();
    }
}

// 实现Thread.UncaughtExceptionHandler 接口,创建异常处理器
public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler{

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("caught " + e);
    }
}

public class HandlerThreadFactory implements ThreadFactory {

    @Override
    public Thread newThread(Runnable r) {
        System.out.println(this + " creating new Thread");
        Thread t = new Thread(r);
        System.out.println("created " + t);
        t.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        System.out.println("ex = " + t.getUncaughtExceptionHandler());
        return t;
    }
}

public class CaptureUncaughtException {

    public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool(new HandlerThreadFactory());
        service.execute(new ExceptionThread2());
    }
}

Add in the program an additional tracking mechanism to verify the thread created by this factory will be passed to UncaughtExceptionHandler, you can see through the uncaught exception uncaughtExceptionto capture.

Article Source:

"Java programming ideas"

https://www.javatpoint.com/join()-method

Guess you like

Origin www.cnblogs.com/cxuanBlog/p/11440959.html