I have two issues please:
1- How can I mutate in-place x_1&x_2 by the returns of fetch ( Z and Y ) to avoid the below error?

A = [1,2,3,4,5]
x_1 = zeros(5); x_2 = zeros(5);
thr = Threads.@spawn begin
Z = A .+ 1;
Y = A .+ 2;
Z, Y
end
x_1, x_2 = fetch(thr); # it works
x_1, x_2 .= fetch(thr); # it gives error
ERROR: MethodError: no method matching copyto!(::Tuple{Vector{Int64}, Vector{Int64}}, ::Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple}, Tuple{Base.OneTo{Int64}}, typeof(identity), Tuple{Tuple{Vector{Int64}, Vector{Int64}}}})
Closest candidates are:

2- Another issue related to variable scope. Why Z&Y were not updated in the snippet code in case-1 while they were updated when the code was put in function f in case-2?

# Case-1
##### snippet Code
Z = zeros(5); Y = zeros(5);
thr = Threads.@spawn begin
Z = A .+ 1;
Y = A .+ 2;
end
fetch(thr)
# Here Z,Y are not updated (still zeros)
##### snippet Code
# Case-2
function f(A)
##### snippet Code
Z = zeros(5); Y = zeros(5);
thr = Threads.@spawn begin
Z = A .+ 1;
Y = A .+ 2;
end
fetch(thr)
# Here Z,Y are updated
##### snippet Code
Z, Y
end
Z, Y = f(A)

The @spawn introduces a local scope block, if you want to assign to globals from local scopes, you need to use global to do so. But ideally, don’t assign to globals at all. Note that you are not mutating Y and Z but reassigning newly allocated arrays to those bindings.

Your first problem has nothing to do with threads or fetch. The error tells you that the broadcast doesn’t know how to copy the contents of the right hand side, a tuple, into the left hand side, a tuple too. That makes sense because tuples are immutable.

Either stick with the assignment, or better yet, write your threaded code to update x_1, x_2 in place.

Because Y,Z are local to the task created by @spawn. There is an anonymous function created that wraps the code. Within that function, e.g. Z = ... is a local assignment and shadows the global variable. You need to annotate with global

Z = zeros(5); Y = zeros(5);
thr = Threads.@spawn begin
global Z = A .+ 1;
global Y = A .+ 2;
end

The task created in the function on the other hand is actually a closure capturing the local A,Y,Z.

julia> A = [1,2,3,4,5];
julia> x_1 = zeros(5); x_2 = zeros(5);
julia> function f!(Y,Z,A)
Threads.@spawn begin
Z .= A .+ 1;
Y .= A .+ 2;
end
end
f! (generic function with 1 method)
julia> f!(x_1, x_2, A) |> wait
julia> x_1
5-element Vector{Float64}:
3.0
4.0
5.0
6.0
7.0