There are many solutions here! Depends a bit on your needs. Among the favorites for your situation would probably be
you can either use a Coroutine
public void OnCollisionEnter2D(Collision2D col) //player collide with bonus
{
    if (col.gameObject.name == "Cube")
    {    
        StartCoroutine (Timer());
    }
}
private IEnumerator Timer()
{
    yield return new WaitForSeconds (3f);
    // Something that happens after 3 seconds
}
You can directly turn the collision message itself into a Coroutine
public IEnumerator OnCollisionEnter2D(Collision2D col) //player collide with bonus
{
    if (col.gameObject.name == "Cube")
    {     
        yield return new WaitForSeconds (3f);
        // Something happens after 3 seconds
    }
}
Or you can use Invoke in order to execute a method after a delay
public void OnCollisionEnter2D(Collision2D col) //player collide with bonus
{
    if (col.gameObject.name == "Cube")
    {     
        Invoke(nameof(AfterDelay), 3f);
    }
}
public void AfterDelay()
{
    // Something happens after 3 seconds
}
For more options and detailed information checkout How make the script wait/sleep in a simple way in unity
If by start a timer you mean e.g. a countdown display then you should definitely go with a Coroutine like e.g.
public Text text;
private Coroutine timer;
public void OnCollisionEnter2D(Collision2D col) //player collide with bonus
{
    if (col.gameObject.name == "Cube")
    {    
        if(timer == null) timer = StartCoroutine (Timer(3f));
    }
}
public void OnCollisionExit2D(Collision2D col) //player left bonus before timer passed
{
    if (col.gameObject.name == "Cube")
    {    
        if(timer == null) StopCoroutine (timer);
        timer = null;
    }
}
private IEnumerator Timer(float durationInSeconds)
{
    var timeLeft = duration;
    while(timeLeft >= 0)
    {
        Text.text = timeLeft.ToString(F2);
        yield return null;
    }
    // Something that happens after the timer reached 0
    Debug.Log("Hello!");
}