简体   繁体   中英

C# vs Java thread-safety

In Java we can do something like

final string str = "I am a string";

Thread thread = new Thread(...{
    string str2 = "bla bla bla " + str;
});

I don't fully understand how to do it, but the point being I need to declare str as final to acces it in my thread so there is no varaible corruption.

But now how does I am supose to do it in C#

string str = "I am a string";

Task.Run(() => {
    string str2 = "bla bla " + str;
});

It does work, but I am not sure it's the right way to do it. I am using Visual Studio for Xamarin.

Let's take a step back.

When you create a lambda in C#, you capture outer variables as variables :

int x = 123;
Action change = () => { Console.WriteLine(x); x = 345; };
Console.WriteLine(x); // 123
change(); // 123
Console.WriteLine(x); // 345
change(); // 345
x = 789;
change(); // 789
Console.WriteLine(x); // 345

There is only one variable x , and it is shared by the lambda and the activation of the method.

This is very useful but there are situations where it can get super confusing :

List<Action> actions = new List<Action>();
for(int x = 0; x < 10; ++x)
{
  actions.Add(() => { Console.WriteLine(x); });
}
actions[0](); // 10, surprise!

There is only one variable x, and all the lambdas share it.

Some people want the first behaviour -- lambdas share variables -- but people who write the second kind of program want the second kind of behaviour. They want lambdas to capture the current value of a variable , not the variable itself .

C# solves this problem by simply choosing the first option. Java solves the problem by making the first scenario illegal . If you can only capture variables that never change then you don't have either the benefits or the problems of capturing variables as variables.

I personally prefer the C# choice, despite its shortcomings. But both are reasonable, justifiable and principled. Different language designers make different choices.

The feature has nothing to do with thread safety per se. (Though there are thread safety aspects to it; variables shared across threads via lambdas in C# are not volatile .) Rather, it's a design decision about how lambda capture of variables works.

I don't fully understand how to do it, but the point being I need to declare str as final to acces it in my thread so there is no varaible corruption.

No, the point is that the thread declaration contains a Java closure and this is how Java closures work, ie they can only be created using immutable ( final ) objects. The problem does not exist in C#.

The equivalent of final in C# is the keyword readonly if it is being used on a field like you are doing or sealed if it is being used on a class or method.

One note is not strictly required for you to use readonly for a variable to be used inside another thread, your code will work as-is right now, but it does ensure you don't accidentally make mistakes that could cause inconsistent behavior because you changed the value of str on some other thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM