Here's a possibility:
\documentclass{book}
\usepackage{amsthm}
\usepackage{xparse}
\usepackage{environ}
\theoremstyle{definition} % body text is upright
\newtheorem{exercise}{Exercise}
\ExplSyntaxOn
\newtheorem*{innersolution}{Solution ~ of ~ \dvvv_exercise_ref:}
\NewEnviron{solution}
{
\seq_gput_right:Nx \g_dvvv_solution_group_seq { {\theexercise}{\exp_not:V \BODY} }
}
\NewDocumentEnvironment{solution*}{}
{
\cs_set:Npx \dvvv_exercise_ref: { \theexercise }
\innersolution
}
{
\endinnersolution
}
\NewDocumentCommand{\printsolutions}{}
{
\seq_map_inline:Nn \g_dvvv_solution_group_seq
{
\dvvv_print_solutions:nn ##1
}
\seq_gclear:N \g_dvvv_solution_group_seq
}
\seq_new:N \g_dvvv_solution_group_seq
\cs_new_protected:Npn \dvvv_print_solutions:nn #1 #2
{
\cs_set:Npn \dvvv_exercise_ref: { #1 }
\begin{innersolution} #2 \end{innersolution}
}
\ExplSyntaxOff
\begin{document}
\chapter{Title}
\section{Exercises}
\begin{exercise}
This is an exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is an exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is an exercise.
\end{exercise}
Some optional text in between.
\begin{solution*}
This is a solution.
\end{solution*}
The solution has been printed immediately, because
\texttt{solution*} has been used.
\begin{exercise}
This is another exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is yet another exercise.
\end{exercise}
\begin{solution}
Too much.
\end{solution}
\section{Solutions}
\printsolutions
\end{document}
The solutions are stored in a FIFO list; using solution* makes the solution print at the spot.

Here's the same, but with support for hyperlinks:
\documentclass{book}
\usepackage{amsthm}
\usepackage{xparse}
\usepackage{environ}
\usepackage[colorlinks]{hyperref}
\theoremstyle{definition} % body text is upright
\newtheorem{innerexercise}{Exercise}
\ExplSyntaxOn
\NewDocumentEnvironment{exercise}{}
{
\innerexercise\label{dvvv_ \theinnerexercise _label}
}
{
\endinnerexercise
}
\newtheorem*{innersolution}{\dvvv_exercise_ref:}
\NewEnviron{solution}
{
\seq_gput_right:Nx \g_dvvv_solution_group_seq
{
{\theinnerexercise}{\exp_not:V \BODY}
}
}
\NewDocumentEnvironment{solution*}{}
{
\cs_set:Npx \dvvv_exercise_ref:
{
\exp_not:N \hyperref
[
dvvv_ \theinnerexercise _label
]
{
Solution~of~\exp_not:N\ref*{dvvv_ \theinnerexercise _label}
}
}
\innersolution
}
{
\endinnersolution
}
\NewDocumentCommand{\printsolutions}{}
{
\seq_map_inline:Nn \g_dvvv_solution_group_seq
{
\dvvv_print_solutions:nn ##1
}
\seq_gclear:N \g_dvvv_solution_group_seq
}
\seq_new:N \g_dvvv_solution_group_seq
\cs_new_protected:Npn \dvvv_print_solutions:nn #1 #2
{
\cs_set:Npn \dvvv_exercise_ref:
{
\hyperref[dvvv_#1_label]{Solution~of~\ref*{dvvv_#1_label}}
}
\begin{innersolution} #2 \end{innersolution}
}
\ExplSyntaxOff
\begin{document}
\chapter{Title}
\section{Exercises}
\begin{exercise}
This is an exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is an exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is an exercise.
\end{exercise}
Some optional text in between.
\begin{solution*}
This is a solution.
\end{solution*}
The solution has been printed immediately, because
\texttt{solution*} has been used.
\begin{exercise}
This is another exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is yet another exercise.
\end{exercise}
\begin{solution}
Too much.
\end{solution}
\section{Solutions}
\printsolutions
\end{document}

Let's look at the first solution step by step. The second just adds setting automatically a label for each exercise environment, to be used for the hyperlink, so it's not much more complicated.
Step 1
Define an exercise environment; this is standard
Step 2
Define an innersolution environment as an unnumbered theorem; the label text depends on the value of \dvvv_exercise_ref: that will be set at printing time
Step 3
Define a solution environment, with the help of \NewEnviron, that makes LaTeX store the environment's content in the macro \BODY. The value of the macro, together with the current exercise number, is stored in a sequence.
Step 4
The solution* environment just sets the value of \dvvv_exercise_ref: to the current exercise number and calls innersolution
Step 5
Define the \printsolutions command, which simply maps the sequence, that is, delivers to \dvvv_print_solutions:nn each of its item. Finally it clears the sequence.
Step 6
The \dvvv_print_solutions:nn function uses the fact that the solutions were stored in the format {<number>}{<contents>}, so it uses the first argument for setting the value of \dvvv_exercise_ref: and feeds the second argument to the innersolution environment.
Links also in the reverse direction (from exercise to solution)
The trick is to add another label at solutions and a hyperlink at the exercise.
\documentclass{book}
\usepackage{amsthm}
\usepackage{xparse}
\usepackage{environ}
\usepackage[colorlinks]{hyperref}
\newtheoremstyle{exercise}% name
{\topsep}% Space above
{\topsep}% Space below
{\normalfont}% Body font
{}% Indent amount (empty = no indent, \parindent = para indent)
{\bfseries}% Thm head font
{.}% Punctuation after thm head
{ }% Space after thm head
{\hyperref[dvvv_#2_reverse_label]{\thmname{#1}\thmnumber{ #2}}\thmnote{ (#3)}}% Thm head spec
\theoremstyle{exercise} % body text is upright
\newtheorem{innerexercise}{Exercise}
\theoremstyle{definition}
\ExplSyntaxOn
\NewDocumentEnvironment{exercise}{}
{
\innerexercise\label{dvvv_ \theinnerexercise _label}
}
{
\endinnerexercise
}
\newtheorem*{innersolution}{\dvvv_exercise_ref:}
\NewEnviron{solution}
{
\seq_gput_right:Nx \g_dvvv_solution_group_seq
{
{\theinnerexercise}{\exp_not:V \BODY}
}
}
\NewDocumentEnvironment{solution*}{}
{
\phantomsection\label{dvvv_ \theinnerexercise _reverse_label}
\cs_set:Npx \dvvv_exercise_ref:
{
\exp_not:N \hyperref
[
dvvv_ \theinnerexercise _label
]
{
Solution~of~\exp_not:N\ref*{dvvv_ \theinnerexercise _label}
}
}
\innersolution
}
{
\endinnersolution
}
\NewDocumentCommand{\printsolutions}{}
{
\seq_map_inline:Nn \g_dvvv_solution_group_seq
{
\dvvv_print_solutions:nn ##1
}
\seq_gclear:N \g_dvvv_solution_group_seq
}
\seq_new:N \g_dvvv_solution_group_seq
\cs_new_protected:Npn \dvvv_print_solutions:nn #1 #2
{
\cs_set:Npn \dvvv_exercise_ref:
{
\phantomsection\label{dvvv_#1_reverse_label}
\hyperref[dvvv_#1_label]{Solution~of~\ref*{dvvv_#1_label}}
}
\begin{innersolution} #2 \end{innersolution}
}
\ExplSyntaxOff
\begin{document}
\chapter{Title}
\section{Exercises}
\begin{exercise}
This is an exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is an exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is an exercise.
\end{exercise}
Some optional text in between.
\begin{solution*}
This is a solution.
\end{solution*}
The solution has been printed immediately, because
\texttt{solution*} has been used.
\begin{exercise}
This is another exercise.
\end{exercise}
\begin{solution}
A solution.
\end{solution}
\begin{exercise}
This is yet another exercise.
\end{exercise}
\begin{solution}
Too much.
\end{solution}
\clearpage
\section{Solutions}
\printsolutions
\end{document}
UPDATE March 2019
With xparse released 2019-03-05 or later, there's no need for environ any longer. Replace the code for solution by
\NewDocumentEnvironment{solution}{+b}
{
\seq_gput_right:Nx \g_dvvv_solution_group_seq
{
{\theinnerexercise}{ \exp_not:n { #1 } }
}
}
{}