One object, two references
You said:
every thread will have an instance member t of class Abs
we have an instance member for every thread
No, not so.
Each of your two Task1 objects holds a reference to an object of type Abs, the very same single object. You instantiated only a single Abs object. Then you passed a reference to each of the new Task1( obj ) calls.
Knowing the difference between an object (a chunk of memory) and a reference (basically, a pointer to that chunk’s location in memory) is crucial here. If you are not clear on this, study the subject.
Since you have only one Abs object in your example app, there is only one int primitive variable named x. So your code is dealing with a single number value. Each of your threads is accessing, and replacing, that value. So your code is not thread-safe.
See also comment by markspace.
Abs obj = new Abs(); // (1) Create one single object. (2) Create a reference to that object. (3) Store that reference in a variable named `obj`.
Task1 t1 = new Task1( obj ); // Pass a *reference* to this constructor.
Task1 t2 = new Task1( obj ); // Pass a *reference* to this constructor. Happens to be the very same reference passed in line above.
// At this point, both `t1` and `t2` hold a reference leading to the same single `Abs` object. One object in memory, two references to that object.

Race condition
The race condition occurs because x++ is not an atomic operation, as discussed here. Three separate operations occur:
- Reading
x.
- Incrementing for a new value.
- Writing the new value back to
x.
Being non-atomic means one thread can read the value of that number, and in an intervening moment, a second thread can both read and increment that same number, writing a new value to the x variable. A moment later, the first thread increments its previously read value, and stores that new value back into x. (Which threads operate in what order for however amount of time between pauses is completely unpredictable!)
So both threads can read a value of 1. And both threads can increment that value to 2. The value 2 can be written twice, once by each of the two threads.
The lesson to learn in concurrency is that any mutable resource shared across threads must be protected. (Simple in concept, tricky in practice.)
AtomicInteger
In your case, one simple way to add that protection is to change your int x primitive to an AtomicInteger object. The AtomicInteger class makes reading, writing, and reporting an integer value atomic.
In Abs class, change the declaration of x. And change the incrementing line x++ to call a method on AtomicInteger instead.
We mark x as final to prevent any reassignment to a different AtomicInteger object. Reassignment would ruin the integrity of our purpose of a rolling counter.
class Abs
{
final AtomicInteger x = new AtomicInteger( 0 ) ;
public void increment ( )
{
int newValue = x.incrementAndGet() ;
System.out.println( newValue );
}
}
A fine point on code above: We instantiate our AtomicInteger as part of the declaration because this guarantees per the Java specification that the code will be run before any other code has a chance to access this member field. Combined with final, we know that all threads will see and access the same single reference stored in x in a thread-safe manner.
By the way, in modern Java we rarely address the Thread class directly. Generally best to use the Executors framework instead.