Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is multithreading and thread safety in java

2025-02-23 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article is about what multithreading and thread safety are in java. The editor thinks it is very practical, so share it with you as a reference and follow the editor to have a look.

What is the process?

There are many separate programs in the computer, each of which has an independent process, and the processes are independent of each other. For example, QQ, KuGou player, PC manager and so on in the following picture.

What is a thread?

If a process wants to perform a task, it needs to rely on threads. In other words, the smallest unit of execution in a process is a thread, and there is at least one thread in a process.

So what is multithreading? When it comes to multithreading, we want to talk about two concepts, serial and parallel. Only by figuring this out can we better understand multithreading.

The so-called serial, in fact, relative to a single thread to perform multiple tasks, let's take the download file as an example: when we download multiple files, it is downloaded in a certain order in the serial, that is to say, we must wait to download A before we can start downloading B. it is impossible for them to overlap in time.

Parallelism: downloading multiple files, starting multiple threads, downloading multiple files at the same time, here is strictly, happening at the same time, parallelism is overlapping in time.

Now that we understand these two concepts, let's talk about what multithreading is. For example, if we open Tencent Butler, Tencent Housekeeping itself is a program, that is to say, it is a process, and there are many functions in it. We can see the following picture, which can check and kill viruses, clean up garbage, computer acceleration and many other functions.

In terms of single threading, whether you want to clean up the garbage or kill the virus, you have to do one of these things before you can do the next thing, which has an order of execution.

If it is multi-threaded, when we clean up the garbage, we can also check and kill viruses, computer acceleration and other operations, which happen at the same time in the strict sense, without the order of execution.

That is, multiple threads are generated when a process is running.

After understanding this problem, we need to understand another problem that we have to consider when using multithreading-thread safety.

Today we will not talk about how to ensure the safety of a thread, let's talk about what is thread safety? Because I was asked in the interview before, to be honest, I really didn't know much about this question before. We only seem to have learned how to ensure a thread safety, but we don't know what the so-called security is!

What is thread safety?

Since it is a thread safety problem, there is no doubt that all the hidden dangers arise in the case of multiple thread access, that is, we need to ensure that when multiple threads are accessed, our program can also execute as we expect, let's take a look at the following code.

Integer count = 0 × public void getCount () {count + +; System.out.println (count);}

For a very simple piece of code, let's count the number of visits to this method and whether there will be any problems when multiple threads are accessed at the same time. I started 3 threads, each thread looped 10 times, and got the following results:

We can see that there are two 26s here, which clearly shows that this method is not thread-safe at all, and there are many reasons for this problem.

The most common one is that our A thread gets the value of count after entering the method, and when we just read this value and haven't changed the value of count, thread B also comes in, so thread An and thread B get the same count value.

So we can see that this is really not a thread-safe class because they all need to manipulate the shared variable. In fact, to give a clear definition of thread safety, or quite complex, we according to our program to summarize what is thread safety.

When multiple threads access a method, no matter how you call it, or how these threads execute alternately, we don't need to do any synchronization in the main program. The resulting behavior of this class is the correct behavior we imagine, so we can say that the class is thread-safe.

After figuring out what thread safety is, let's take a look at the two most common ways to ensure thread safety in Java. Let's take a look at the code first.

Public void threadMethod (int j) {int I = 1; j = j + I;}

Do you think this code is thread-safe?

There is no doubt that it is absolutely thread-safe. Let's analyze why it is thread-safe.

We can see that this code does not have any state, that is to say, our code does not contain any scope, nor does it refer to fields in other classes. the scope and result of its execution only exist in the local variable of its thread and can only be accessed by the executing thread. The access of the current thread does not have any effect on another thread accessing the same method.

Two threads access this method at the same time, because there is no shared data, so the behavior between them will not affect the operations and results of other threads, so stateless objects are also thread-safe.

What about adding a status?

If we add a state to this code, add a count, to record the number of hits of this method, each time count+1 is requested, is the thread still safe at this time?

Public class ThreadDemo {int count = 0; / / number of hits of the recording method public void threadMethod (int j) {count++; int I = 1; j = j + I;}}

Obviously not, there is no problem with single thread running, but when multiple threads access this method concurrently, the problem arises. Let's analyze the count+1 operation first.

After entering this method, you first need to read the value of count, then modify the value of count, and then assign this value to count, which involves a total of three steps: "read" one > "modify" one > "assign". Since this process is step-by-step, let's first look at the following figure to see if you can see the problem:

It can be found that the value of count is not the correct result, when thread A reads the value of count, but has not yet modified it, thread B has already come in, and thread B still reads the value of count 1. Because of this, our count value has been deviated, so there are a lot of hidden dangers when such programs are put in our code.

How to ensure thread safety?

Since there is a thread safety problem, then we must find a way to solve this problem, how to solve it? Let's talk about a few common ways.

1 、 synchronized

The synchronized keyword is used to control thread synchronization, to ensure that our threads are not executed by multiple threads at the same time in a multi-threaded environment, and to ensure the integrity of our data.

Public class ThreadDemo {int count = 0; / / number of hits of the recording method public synchronized void threadMethod (int j) {count++; int I = 1; j = j + I;}}

This ensures that our threads are synchronized. At the same time, we need to pay attention to a problem that we usually ignore. First, synchronized locks the object in parentheses, not the code. Secondly, for non-static synchronized methods, the lock is the object itself, that is, this.

When synchronized locks an object, if another thread wants to acquire the lock object, it must wait until the thread releases the lock object, otherwise it will be in a waiting state all the time.

Note: although adding the synchronized keyword can make our threads safe, but when we use it, we should also pay attention to reducing the scope of use of synchronized, if random use affects the performance of the program, other objects want to get the lock, as a result, you do not use the lock all the time, which is a bit of a waste of resources.

2 、 Lock

First of all, let's talk about the difference between it and synchronized. Lock was introduced in Java1.6. The introduction of Lock makes the lock operable. What do you mean? That is, we can manually acquire and release locks when needed, and even interrupt the synchronization features of acquisition and timeout acquisition, but Lock is obviously not as convenient and fast as synchronized in terms of use. Let's first take a look at how it is generally used:

Private Lock lock = new ReentrantLock (); / / ReentrantLock is a subclass of Lock private void method (Thread thread) {lock.lock (); / / acquire lock object try {System.out.println ("thread name: + thread.getName () +" acquired lock "); / / Thread.sleep (2000);} catch (Exception e) {e.printStackTrace () } finally {System.out.println ("thread name:" + thread.getName () + "lock released"); lock.unlock (); / / release lock object}}

To enter the method, we first need to acquire the lock, and then execute our business code. Unlike synchronized, the object acquired by Lock needs to be released by us personally. In order to prevent our code from being abnormal, our release lock operation is placed in finally, because the code in finally will be executed anyway.

Write a main method and start two threads to test whether our program is working properly:

Public static void main (String [] args) {LockTest lockTest = new LockTest (); / / Thread 1 Thread T1 = new Thread (new Runnable () {@ Override public void run () {/ / Thread.currentThread () returns the reference lockTest.method (Thread.currentThread ()) of the current thread;}}, "T1") / / Thread 2 Thread T2 = new Thread (new Runnable () {@ Override public void run () {lockTest.method (Thread.currentThread ());}}, "T2"); t1.start (); t2.start ();}

Results:

We can see that there is no problem with our implementation.

In fact, there are several ways to acquire locks in Lock. Let's say another one here, that is, the method of tryLock () is different from Lock (). When Lock acquires the lock, if it can't get the lock, it waits until it gets the lock, but tryLock () is not like this. TryLock has a return value of Boolean. If you don't get the lock, go back to false and stop waiting. It doesn't wait for the lock to be acquired as Lock () does.

Let's take a look at the code:

Private void method (Thread thread) {/ / lock.lock (); / / acquire lock object if (lock.tryLock ()) {try {System.out.println ("thread name: + thread.getName () +" acquired lock "); / / Thread.sleep (2000);} catch (Exception e) {e.printStackTrace () } finally {System.out.println ("thread name:" + thread.getName () + "lock released"); lock.unlock (); / / release lock object}

The result: we continue to test with the two threads just now, and we can find that after thread T1 acquires the lock, thread T2 comes in immediately and finds that the lock is occupied, so it is no longer waiting.

It seems that this method doesn't feel perfect. If my first thread takes longer to get the lock than the second thread, will I not get the lock object either?

Can I use one way to control it, so that the waiting thread can wait for 5 seconds, and if after 5 seconds, the lock cannot be acquired, then stop waiting. In fact, tryLock () can set the corresponding waiting time.

Private void method (Thread thread) throws InterruptedException {/ / lock.lock (); / / get the lock object / / if you can't get the lock object within 2 seconds, don't wait for if (lock.tryLock (2memeUnit.SECONDS)) {try {System.out.println ("Thread name:" + thread.getName () + "acquired lock") / / sleep here for 3 seconds Thread.sleep (3000);} catch (Exception e) {e.printStackTrace ();} finally {System.out.println ("thread name:" + thread.getName () + "released lock"); lock.unlock () / / release lock object}

Result: looking at the code above, we can find that although we can wait 2 seconds when we acquire the lock object, it takes 3 seconds for our thread T1 to execute the task after acquiring the lock object. so thread T2 is not waiting at this time.

Let's change the waiting time to 5 seconds, and then take a look at the results:

Private void method (Thread thread) throws InterruptedException {/ / lock.lock (); / / get the lock object / / if you can't get the lock object within 5 seconds, then don't wait for if (lock.tryLock (5meme TimeUnit. Second)) {try {System.out.println ("thread name:" + thread.getName () + "acquired lock") } catch (Exception e) {e.printStackTrace ();} finally {System.out.println ("Thread name: + thread.getName () +" released the lock "); lock.unlock (); / / release lock object}

The result: at this time, we can see that thread T2 waits for 5 seconds to acquire the lock object and execute the task code.

That's how we use Lock to keep our threads safe.

Thank you for reading! This is the end of this article on "what is multithreading and thread safety in java". I hope the above content can be of some help to you, so that you can learn more knowledge. if you think the article is good, you can share it out for more people to see!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report