Because many embedded programming environments do not use operating systems I generally avoid threads for dealing with this sort of situation. (threads are a perfectly valid and useful approach in those environments)
In your main loop (either explicit in Simple or implicit in Iterative) just check the time you start and the current time, e.g.: (all from memory, and I usualy code C, so treat this as pseudocode)
Code:
double pistonTimer = 0.0;
while (isTeleop() && isEnabled()){//implicit in Iterative
//check for the condition that starts the piston
if (joystick1.RawButton(5)){
//...stuff that turns on/off the right solenoids...
pistonTimer = Timer.GetTime();//I believe this is now a double, in seconds
}
//lots of other things like driving code mixed in
//check if its done yet
if (pistonTimer > 0.0 //important so you know you've started timing
&& Timer.GetTime() - pistonTimer > 2.0){
//...stuff that turns on/off the other right solenoids...
pistonTimer = 0.0; //don't forget to reset it
}
}
While polling like this isn't super efficient it is easy to implement and follow.
HTH