diff --git a/note/cycle.txt b/note/cycle.txt
deleted file mode 100644
index 47ad4b11a65ed7e9cc03153878a90ef53c03c950..0000000000000000000000000000000000000000
--- a/note/cycle.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-init :
-    base
-    on_init
-
-    syncro
-
-
-
-cycle :
-
-    on cycle begin
-    syncro
-
-    agent action
-    syncro
-
-    on cycle end
-    syncro
\ No newline at end of file
diff --git a/note/how to use b/note/how to use
deleted file mode 100644
index 94ec796203c44ddf49dde3ed98cd17efdeed89b5..0000000000000000000000000000000000000000
--- a/note/how to use	
+++ /dev/null
@@ -1,13 +0,0 @@
-1 - create env
-2 - create amas
-3 - amas.start()
-
-to end :
-amas.exit_program()
-
-
-to start :
-amas.put_token()
-
-to stop :
-amas.take_token()
\ No newline at end of file
diff --git a/pyAmakCore/classes/agent.py b/pyAmakCore/classes/agent.py
index f5a979cee0771987c76cec4463613dcfcb34b811..a94ae7537228f8cfdb18a9310e353e1598082239 100644
--- a/pyAmakCore/classes/agent.py
+++ b/pyAmakCore/classes/agent.py
@@ -7,12 +7,10 @@ from typing import List
 import sys
 import pathlib
 
-
 sys.path.insert(0, str(pathlib.Path(__file__).parent))
 
 from pyAmakCore.exception.override import ToOverrideWarning
 from pyAmakCore.enumeration.agent_phase import Phase
-from pyAmakCore.enumeration.executionPolicy import ExecutionPolicy
 
 
 class Agent:
@@ -116,7 +114,13 @@ class Agent:
         """
         return -inf
 
-    def _get_most_critical_neighbor(self, including_me: bool = False) -> 'Agent':
+    def set_criticality(self, criticality: float) -> None:
+        """
+        set agent criticality to criticality
+        """
+        self.__criticality = criticality
+
+    def get_most_critical_neighbor(self, including_me: bool = False) -> 'Agent':
         """
         Convenient method giving the most critical neighbor at a given moment
         """
@@ -135,10 +139,6 @@ class Agent:
 
         return criticalest[randint(0, len(criticalest) - 1)]
 
-    """
-    Cycle
-    """
-
     def on_cycle_begin(self) -> None:
         """
         this method is called by each agent at the start of their cycle
@@ -169,24 +169,10 @@ class Agent:
         """
         ToOverrideWarning("on_act")
 
-    def _phase1(self) -> None:
-        """
-        this is the first phase of a cycle
-        """
-        self.on_perceive()
-        self.__criticality = self.compute_criticality()
-        self._next_phase()
-
-    def _phase2(self) -> None:
+    def next_phase(self) -> None:
         """
-        this is the second phase of a cycle
+        set agent phase to the next phase
         """
-        self.on_decide()
-        self.on_act()
-        self.__criticality = self.compute_criticality()
-        self._next_phase()
-
-    def _next_phase(self):
         next_phase = {
             Phase.INITIALIZING: Phase.PERCEPTION,
             Phase.PERCEPTION: Phase.PERCEPTION_DONE,
@@ -196,32 +182,6 @@ class Agent:
         }
         self.__phase = next_phase.get(self.__phase)
 
-    def run(self) -> None:
-        """
-        Full cycle of an agent
-        """
-        self._next_phase()
-
-        execution_policy = self.__amas.get_execution_policy()
-
-        if execution_policy == ExecutionPolicy.TWO_PHASES:
-            if self.__phase == Phase.PERCEPTION:
-                self.on_cycle_begin()
-                self._phase1()
-                return
-
-            if self.__phase == Phase.DECISION_AND_ACTION:
-                self._phase2()
-                self.on_cycle_end()
-                return
-
-        if execution_policy == ExecutionPolicy.ONE_PHASE:
-            self.on_cycle_begin()
-            self._phase1()
-            self._next_phase()
-            self._phase2()
-            self.on_cycle_end()
-
     def __eq__(self, other: 'Agent') -> bool:
         # check class
         if other is None:
diff --git a/pyAmakCore/classes/amas.py b/pyAmakCore/classes/amas.py
index d24b11510190a8bbb38eae15c38fba0080166e53..7a460931b4116cf7aa36716b6aa64d51a5ac0c36 100644
--- a/pyAmakCore/classes/amas.py
+++ b/pyAmakCore/classes/amas.py
@@ -1,18 +1,15 @@
 """
 Amas Class
 """
-from threading import Thread
 from typing import List
 
 import sys
 import pathlib
 
-
 sys.path.insert(0, str(pathlib.Path(__file__).parent))
 
 from pyAmakCore.classes.tools.loggable import Loggable
-from pyAmakCore.classes.schedulable import Schedulable
-from pyAmakCore.classes.scheduler import Scheduler
+from pyAmakCore.classes.tools.schedulable import Schedulable
 from pyAmakCore.classes.environment import Environment
 from pyAmakCore.classes.agent import Agent
 from pyAmakCore.enumeration.executionPolicy import ExecutionPolicy
@@ -24,43 +21,53 @@ class Amas(Schedulable, Loggable):
     Amas Class
     """
 
-    def __init__(self, environment: Environment) -> None:
+    def __init__(self,
+                 environment: Environment,
+                 execution_policy: ExecutionPolicy = ExecutionPolicy.ONE_PHASE
+                 ) -> None:
 
         Schedulable.__init__(self)
         Loggable.__init__(self)
         self.__environment: Environment = environment
+
         self.__agents: List[Agent] = []
         self.__agent_to_add: List[Agent] = []
         self.__agent_to_remove: List[Agent] = []
 
-        self.__nbrcycle: int = 0
-
-        self.__scheduler: Scheduler = Scheduler()
-        self.__scheduler.add_schedulable(self)
-        self.__environment.add_scheduler(self.__scheduler)
-
-        self.__execution_policy: ExecutionPolicy = ExecutionPolicy.ONE_PHASE
+        self.__execution_policy: ExecutionPolicy = execution_policy
 
+        self.on_initialization()
         self.on_initial_agents_creation()
 
+    def add_pending_agent(self) -> List[Agent]:
+        """
+        add pending agent into agent and return added agents
+        """
         for agent in self.__agent_to_add:
-            if agent not in self.__agents:
-                self.__agents.append(agent)
-        self.__agent_to_add = []
-
-        for agent in self.__agents:
             agent.compute_criticality()
+            self.__agents.append(agent)
+        tmp = self.__agent_to_add
+        self.__agent_to_add = []
+        return tmp
 
-        self.on_initialization()
+    def remove_pending_agent(self):
+        """
+        add pending agent into agent and return removed agents
+        """
+        for agent in self.__agent_to_remove:
+            self.__agents.remove(agent)
+        tmp = self.__agent_to_remove
+        self.__agent_to_remove = []
 
-        # tell scheduler that init is done
-        self.give_token_syncro()
+        return tmp
 
     def add_agent(self, agent: 'Agent') -> None:
         """
         add agent in the amas agents list without duplicate
         """
-        if agent in self.__agents or agent in self.__agent_to_add:
+        if agent in self.__agents:
+            return
+        if agent in self.__agent_to_add:
             return
         self.__agent_to_add.append(agent)
 
@@ -75,6 +82,10 @@ class Amas(Schedulable, Loggable):
         """
         remove agent from amas
         """
+        if agent not in self.__agents:
+            return
+        if agent in self.__agent_to_remove:
+            return
         self.__agent_to_remove.append(agent)
 
     def get_environment(self) -> Environment:
@@ -95,104 +106,9 @@ class Amas(Schedulable, Loggable):
         """
         return self.__execution_policy
 
-    def set_execution_policy(self, execution_policy: ExecutionPolicy) -> None:
-        """
-        set system execution_policy
-        """
-        self.__execution_policy = execution_policy
-
-    def get_cycle(self) -> int:
-        """
-        return nbr of cycle
-        """
-        return self.__nbrcycle
-
     def on_initial_agents_creation(self) -> None:
         """
         This method is called at the end of __init__()
         """
         ToOverrideWarning("on_initial_agents_creation")
 
-    def synchronization(self) -> None:
-        """
-        Unlock Scheduler and wait for his response
-        """
-        self.give_token_syncro()
-        self.__scheduler.take_amas_token()
-
-    def cycle(self) -> None:
-        """
-        Main behavior of Amas
-        """
-        print("Cycle : ", self.__nbrcycle)
-
-        for agent in self.__agent_to_add:
-            if agent not in self.__agents:
-                self.__agents.append(agent)
-        self.__agent_to_add = []
-
-        self.on_cycle_begin()
-        self.synchronization()
-
-        threads = []
-        # suffle
-        for agent in self.__agents:
-            current_thread = Thread(target=agent.run)
-            threads.append(current_thread)
-            current_thread.start()
-
-        for thread in threads:
-            thread.join()
-
-        if self.__execution_policy == ExecutionPolicy.TWO_PHASES:
-            threads = []
-            for agent in self.__agents:
-                current_thread = Thread(target=agent.run)
-                threads.append(current_thread)
-                current_thread.start()
-
-            for thread in threads:
-                thread.join()
-
-        self.synchronization()
-
-        self.on_cycle_end()
-
-        for agent in self.__agent_to_remove:
-            if agent in self.__agents:
-                self.__agents.remove(agent)
-        self.__agent_to_remove = []
-
-        self.to_csv(self.get_cycle(), self.get_agents())
-        self.__nbrcycle += 1
-
-    def put_token(self) -> None:
-        """
-        Tell scheduler to start
-        """
-        self.__scheduler.give_semaphore_start_stop()
-
-    def take_token(self) -> None:
-        """
-        Tell scheduler to stop
-        """
-        self.__scheduler.take_semaphore_start_stop()
-
-    def exit_program(self) -> None:
-        """
-        exit the program at the end of the cycle
-        """
-        self.put_token()
-        self.__scheduler.exit_bool = True
-
-    def set_sleep(self, sleep_time) -> None:
-        """
-        set sleep between 2 cycles
-        """
-        self.__scheduler.sleep_time = sleep_time
-
-    def start(self) -> None:
-        """
-        launch the system
-        """
-        self.__scheduler.run()
diff --git a/pyAmakCore/classes/communicating_agent.py b/pyAmakCore/classes/communicating_agent.py
index 0dbbede2b325a6c723127be266980d7224fc0a42..e31b4ccce66e9a84a2856456e0f0e25c8558610e 100644
--- a/pyAmakCore/classes/communicating_agent.py
+++ b/pyAmakCore/classes/communicating_agent.py
@@ -5,10 +5,9 @@ from typing import Any, List
 import pathlib
 import sys
 
-from pyAmakCore.exception.mailbox import ReceiverIsNotSelf, ReceiverDontExist
-
 sys.path.insert(0, str(pathlib.Path(__file__).parent))
 
+from pyAmakCore.exception.mailbox import ReceiverIsNotSelf, ReceiverDontExist
 from pyAmakCore.classes.agent import Agent
 
 
@@ -108,16 +107,6 @@ class CommunicatingAgent(Agent):
         """
         self.__mailbox.receive_mail(mail)
 
-    def _phase1(self):
-        """
-        Override of phase 1 agent so he read mail before he perceive
-        this is the first phase of a cycle
-        """
-        self.read_mails()
-        self.on_perceive()
-        self.compute_criticality()
-        self._next_phase()
-
     def read_mails(self) -> None:
         """
         method that open all mail in the mailbox
diff --git a/pyAmakCore/classes/environment.py b/pyAmakCore/classes/environment.py
index 52c7727c464fe8b370087be926fc7a4d30068956..ba45fa2fbd31d064e5fa9da62ff08b4020cfff64 100644
--- a/pyAmakCore/classes/environment.py
+++ b/pyAmakCore/classes/environment.py
@@ -3,10 +3,10 @@ Environment class
 """
 import sys
 import pathlib
+
 sys.path.insert(0, str(pathlib.Path(__file__).parent))
 
-from pyAmakCore.classes.schedulable import Schedulable
-from pyAmakCore.classes.scheduler import Scheduler
+from pyAmakCore.classes.tools.schedulable import Schedulable
 
 
 class Environment(Schedulable):
@@ -16,34 +16,4 @@ class Environment(Schedulable):
 
     def __init__(self) -> None:
         super().__init__()
-        self.__scheduler: Scheduler = None
         self.on_initialization()
-        # tell scheduler that init is done
-        self.give_token_syncro()
-
-    def add_scheduler(self, scheduler: Scheduler) -> None:
-        """
-        set scheduler pointer to scheduler
-        add add self to schedulables of scheduler
-        """
-        self.__scheduler = scheduler
-        self.__scheduler.add_schedulable(self)
-
-    def synchronization(self) -> None:
-        """
-        Unlock Scheduler and wait for his response
-        """
-        self.give_token_syncro()
-        self.__scheduler.take_environment_token()
-
-    def cycle(self) -> None:
-        """
-        Main behavior of Environment
-        """
-        self.on_cycle_begin()
-        self.synchronization()
-
-        # mileu de cycle
-        self.synchronization()
-
-        self.on_cycle_end()
diff --git a/pyAmakCore/classes/scheduler.py b/pyAmakCore/classes/scheduler.py
index a7c2b593b4f8147a604246af37fbc3c41ee366f4..b16b13ffedf7dd8bfbaedff0972635e1364138a6 100644
--- a/pyAmakCore/classes/scheduler.py
+++ b/pyAmakCore/classes/scheduler.py
@@ -1,14 +1,17 @@
 """
 Scheduler class
 """
-from threading import Semaphore, Thread
-from time import sleep
-from typing import List
 import sys
 import pathlib
+import pickle
+from threading import Semaphore, Thread
+from time import sleep
+
 sys.path.insert(0, str(pathlib.Path(__file__).parent))
 
-from pyAmakCore.classes.schedulable import Schedulable
+from pyAmakCore.classes.amas import Amas
+from pyAmakCore.classes.scheduler_tool.schedulable_thread import SchedulableThread
+from pyAmakCore.classes.scheduler_tool.amas_thread import AmasThread
 
 
 class Scheduler:
@@ -16,104 +19,124 @@ class Scheduler:
     Scheduler class, to make sure that environment and amas are always sync together
     """
 
-    def __init__(self) -> None:
+    def __init__(self, amas: Amas) -> None:
+        self.amas: Amas = amas
 
-        # List of all schedulables
-        self.__schedulables: List[Schedulable] = []
-        # Sleep timer between 2 cycle
-        self.sleep_time: float = 0
+        self.exit_bool = False
 
-        # Semaphore for start/stop button
-        self.__semaphore_start_stop: Semaphore = Semaphore(0)
-        # Semaphore to tell amas to continue
-        self.__semaphore_amas: Semaphore = Semaphore(0)
-        # Semaphore to tell environment to continue
-        self.__semaphore_environment: Semaphore = Semaphore(0)
+        self.semaphore_start_stop = Semaphore(0)
 
-        self.exit_bool = False
+        self.schedulables = []
+        self.schedulables_threads = []
 
-    def add_schedulable(self, schedulable: Schedulable) -> None:
-        """
-        add schedulable in schedulables list
-        """
-        self.__schedulables.append(schedulable)
+        self.add_schedulables(amas, AmasThread)
+        self.add_schedulables(amas.get_environment(), SchedulableThread)
 
-    def take_amas_token(self) -> None:
-        """
-        make amas wait here for a token
-        """
-        self.__semaphore_amas.acquire()
+        self.sleep_time = 0
 
-    def give_amas_token(self) -> None:
-        """
-        unlock amas
-        """
-        self.__semaphore_amas.release()
+    def get_amas(self):
+        return self.amas
+
+    def add_schedulables(self, schedulable, cls):
+        schedulable_thread = cls(schedulable)
+        self.schedulables.append(schedulable_thread)
+        current_thread = Thread(target=schedulable_thread.run)
+        self.schedulables_threads.append(current_thread)
+        current_thread.start()
 
-    def take_environment_token(self) -> None:
+    def wait_schedulables(self) -> None:
         """
-        make environment wait here for a token
+        wait for all schedulable to release a token
         """
-        self.__semaphore_environment.acquire()
+        for schedulable in self.schedulables:
+            schedulable.action_done.acquire()
 
-    def give_environment_token(self) -> None:
+    def start_schedulables(self) -> None:
         """
-        unlock environment
+        wait for all schedulable to release a token
         """
-        self.__semaphore_environment.release()
+        for schedulable in self.schedulables:
+            schedulable.is_waiting.release()
 
-    def take_semaphore_start_stop(self) -> None:
+    def first_part(self) -> None:
         """
-        Scheduler will wait for a token to start the cycle
+        first part of a cycle
         """
-        self.__semaphore_start_stop.acquire()
+        self.start_schedulables()
+        # on cycle begin
+        self.wait_schedulables()
 
-    def give_semaphore_start_stop(self) -> None:
+    def main_part(self) -> None:
         """
-        give a token to unlock Scheduler
+        main part of a cycle
         """
-        self.__semaphore_start_stop.release()
+        self.start_schedulables()
+        # agent cycle
+        self.wait_schedulables()
 
-    def syncro_schedulable(self) -> None:
+    def last_part(self) -> None:
         """
-        wait for all schedulable to release a token
+        last part of a cycle
         """
-        for schedulable in self.__schedulables:
-            schedulable.take_token_syncro()
+        self.start_schedulables()
+        # on cycle end
+        self.wait_schedulables()
 
     def run(self) -> None:
         """
         main part of amak core
         """
-        # wait that all schedulable are ready
-        self.syncro_schedulable()
-
         while not self.exit_bool:
+            print("Cycle : ", self.amas.get_cycle())
 
-            self.__semaphore_start_stop.acquire()
+            self.semaphore_start_stop.acquire()
             if self.exit_bool:
-                return
-            self.__semaphore_start_stop.release()
+                break
+            self.semaphore_start_stop.release()
+
+            self.first_part()
+            self.main_part()
+            self.last_part()
+
+            sleep(self.sleep_time)
+        self.close_childs()
 
-            threads = []
-            for schedulable in self.__schedulables:
-                current_thread = Thread(target=schedulable.run)
-                threads.append(current_thread)
-                current_thread.start()
+    def close_childs(self):
+        for schedulable in self.schedulables:
+            schedulable.exit_bool = True
+            schedulable.is_waiting.release()
+        for thread in self.schedulables_threads:
+            thread.join(0)
 
-            # on cycle begin
-            self.syncro_schedulable()
-            self.give_amas_token()
-            self.give_environment_token()
+    """
+    program interface
+    """
 
-            # main part of the cycle
-            self.syncro_schedulable()
-            self.give_amas_token()
-            self.give_environment_token()
+    def exit_program(self):
+        self.exit_bool = True
+        self.semaphore_start_stop.release()
 
-            # on cycle end
+    def start(self):
+        self.semaphore_start_stop.release()
 
-            for thread in threads:
-                thread.join()
+    def stop(self):
+        self.semaphore_start_stop.acquire()
+
+    def set_sleep(self, sleep_time: int):
+        self.sleep_time = sleep_time
+
+    """
+    load & save program
+    """
+
+    def save(self):
+        with open('filename.pickle', 'wb') as handle:
+            pickle.dump(self.amas, handle, protocol=pickle.HIGHEST_PROTOCOL)
+
+    @classmethod
+    def load(cls):
+        with open('filename.pickle', 'rb') as handle:
+            amas_object = pickle.load(handle)
+
+        return cls(amas_object)
 
-            sleep(self.sleep_time)
diff --git a/pyAmakCore/classes/scheduler_tool/__init__.py b/pyAmakCore/classes/scheduler_tool/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/pyAmakCore/classes/scheduler_tool/agent_thread.py b/pyAmakCore/classes/scheduler_tool/agent_thread.py
new file mode 100644
index 0000000000000000000000000000000000000000..72098d2bb31d8433ac47ee3525e97e3e5b680b1d
--- /dev/null
+++ b/pyAmakCore/classes/scheduler_tool/agent_thread.py
@@ -0,0 +1,74 @@
+"""
+Class Agent thread
+"""
+from threading import Semaphore
+import sys
+import pathlib
+
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+
+from pyAmakCore.classes.communicating_agent import CommunicatingAgent
+from pyAmakCore.classes.agent import Agent
+from pyAmakCore.enumeration.executionPolicy import ExecutionPolicy
+
+
+class AgentThread:
+    """
+    thread class used to thread agent
+    """
+    action_done = Semaphore(0)
+    execution_policy = ExecutionPolicy.ONE_PHASE
+
+    def __init__(self, agent: Agent):
+
+        self.agent: Agent = agent
+        self.is_waiting: Semaphore = Semaphore(0)
+        self.exit_bool: bool = False
+
+    def phase1(self) -> None:
+        """
+        this is the first phase of a cycle
+        """
+        if isinstance(self.agent, CommunicatingAgent):
+            self.agent.read_mails()
+
+        self.agent.on_perceive()
+        self.agent.set_criticality(self.agent.compute_criticality())
+        self.agent.next_phase()
+
+    def phase2(self) -> None:
+        """
+        this is the second phase of a cycle
+        """
+        self.agent.on_decide()
+        self.agent.on_act()
+        self.agent.set_criticality(self.agent.compute_criticality())
+        self.agent.next_phase()
+
+    def run(self) -> None:
+        """
+        main part of an agent thread
+        """
+        while not self.exit_bool:
+
+            self.is_waiting.acquire()
+            if self.exit_bool:
+                return
+
+            self.agent.next_phase()
+            self.agent.on_cycle_begin()
+
+            self.phase1()
+
+            if AgentThread.execution_policy == ExecutionPolicy.TWO_PHASES:
+                AgentThread.action_done.release()
+                self.is_waiting.acquire()
+
+            self.agent.next_phase()
+
+            self.phase2()
+
+            self.agent.on_cycle_end()
+
+            AgentThread.action_done.release()
diff --git a/pyAmakCore/classes/scheduler_tool/amas_thread.py b/pyAmakCore/classes/scheduler_tool/amas_thread.py
new file mode 100644
index 0000000000000000000000000000000000000000..1d70f237eca2a161bff77ff0eafde8878cb23d7c
--- /dev/null
+++ b/pyAmakCore/classes/scheduler_tool/amas_thread.py
@@ -0,0 +1,122 @@
+"""
+thread class for amas
+"""
+from threading import Thread
+from typing import List
+
+import sys
+import pathlib
+
+from pyAmakCore.enumeration.executionPolicy import ExecutionPolicy
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+
+from pyAmakCore.classes.scheduler_tool.agent_thread import AgentThread
+from pyAmakCore.classes.amas import Amas
+from pyAmakCore.classes.agent import Agent
+from pyAmakCore.classes.scheduler_tool.schedulable_thread import SchedulableThread
+
+
+class AmasThread(SchedulableThread):
+    """
+    thread class used to thread amas
+    """
+
+    def __init__(self, amas: Amas) -> None:
+        super().__init__(amas)
+
+        self.agents: List[AgentThread] = []
+        self.agents_thread: List[Thread] = []
+
+        AgentThread.execution_policy = self.schedulable.get_execution_policy()
+
+        self.schedulable.add_pending_agent()
+        for agent in self.schedulable.get_agents():
+            self.add_agent(agent)
+
+    def add_agent(self, agent: Agent) -> None:
+        """
+        make agent a thread and start the thread
+        """
+        agent_thread = AgentThread(agent)
+        self.agents.append(agent_thread)
+        current_thread = Thread(target=agent_thread.run)
+        self.agents_thread.append(current_thread)
+        current_thread.start()
+
+    def add_agents(self) -> None:
+        """
+        if there are new agents, add them
+        """
+        added_agent = self.schedulable.add_pending_agent()
+        for agent in added_agent:
+            self.add_agent(agent)
+
+    def remove_agents(self) -> None:
+        """
+        if some agents are removed, close their thread
+        """
+        removed_agent = self.schedulable.remove_pending_agent()
+        for agent in removed_agent:
+            for i in range(len(self.agents)):
+                if agent == self.agents[i].agent:
+                    self.agents[i].exit_bool = True
+                    self.agents[i].is_waiting.release()
+                    self.agents_thread[i].join()
+
+                    self.agents.remove(self.agents[i])
+                    self.agents_thread.remove(self.agents_thread[i])
+
+    def on_cycle_begin(self) -> None:
+        """
+        start of cycle
+        """
+        self.add_agents()
+        self.schedulable.on_cycle_begin()
+
+    def main_cycle_part(self) -> None:
+        """
+        main part of the cycle
+        """
+        for agent in self.agents:
+            agent.is_waiting.release()
+        # agent cycle
+
+        if self.schedulable.get_execution_policy() == ExecutionPolicy.TWO_PHASES:
+            # wait agents
+            for i in range(len(self.agents)):
+                AgentThread.action_done.acquire()
+            # start phase 2 for all agents
+            for agent in self.agents:
+                agent.is_waiting.release()
+
+        for i in range(len(self.agents)):
+            AgentThread.action_done.acquire()
+
+    def on_cycle_end(self) -> None:
+        """
+        end of cycle
+        """
+        self.schedulable.on_cycle_end()
+
+        self.remove_agents()
+        self.schedulable.to_csv(self.schedulable.get_cycle(), self.schedulable.get_agents())
+
+        self.schedulable.cycle()
+
+    def run(self) -> None:
+        super().run()
+        self.close_child()
+
+    def close_child(self) -> None:
+        """
+        tell all child threads to close
+        """
+        for agent in self.agents:
+            agent.exit_bool = True
+            agent.is_waiting.release()
+
+        for thread in self.agents_thread:
+            thread.join(0)
+
+
diff --git a/pyAmakCore/classes/scheduler_tool/schedulable_thread.py b/pyAmakCore/classes/scheduler_tool/schedulable_thread.py
new file mode 100644
index 0000000000000000000000000000000000000000..17f347ab275403fbe548ec6390baeab4b8e4525a
--- /dev/null
+++ b/pyAmakCore/classes/scheduler_tool/schedulable_thread.py
@@ -0,0 +1,53 @@
+"""
+thread class for Schedulable
+"""
+from threading import Semaphore
+
+import sys
+import pathlib
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+
+from pyAmakCore.classes.tools.schedulable import Schedulable
+
+
+class SchedulableThread:
+    """
+    thread class used to thread schedulable
+    """
+
+    def __init__(self, schedulable: Schedulable):
+
+        self.schedulable: Schedulable = schedulable
+        self.is_waiting: Semaphore = Semaphore(0)
+        self.exit_bool: bool = False
+        self.action_done: Semaphore = Semaphore(0)
+
+    def on_cycle_begin(self):
+        self.schedulable.on_cycle_begin()
+
+    def main_cycle_part(self):
+        pass
+
+    def on_cycle_end(self):
+        self.schedulable.on_cycle_end()
+        self.schedulable.cycle()
+
+    def run(self) -> None:
+        """
+        main part of a schedulable thread
+        """
+        while not self.exit_bool:
+            self.is_waiting.acquire()
+            if self.exit_bool:
+                break
+            self.on_cycle_begin()
+            self.action_done.release()
+
+            self.is_waiting.acquire()
+            self.main_cycle_part()
+            self.action_done.release()
+
+            self.is_waiting.acquire()
+            self.on_cycle_end()
+            self.action_done.release()
diff --git a/pyAmakCore/classes/tools/amasIHM.py b/pyAmakCore/classes/tools/amasIHM.py
deleted file mode 100644
index 5c1a6889566a7cf70374a6cfc999547e0ffe48cf..0000000000000000000000000000000000000000
--- a/pyAmakCore/classes/tools/amasIHM.py
+++ /dev/null
@@ -1,36 +0,0 @@
-"""
-Amas class that need to be used for pyAmakIhm
-"""
-from pyAmakCore.classes.amas import Amas
-from pyAmakCore.classes.environment import Environment
-
-
-class AmasIHM(Amas):
-    """
-    Convenient class to override while using pyAmakIHM
-    """
-
-    def __init__(self, environment: Environment):
-        self.__observer = None
-        super().__init__(environment)
-
-    def get_Agents_Sorted(self):
-        """
-        sort agent by id
-        """
-        agents = self.get_agents()
-        agents.sort(key=lambda x: x.get_id())
-        return agents
-
-    def cycle(self) -> None:
-        """
-        override amas cycle, to update obsever after each cycle
-        """
-        super().cycle()
-        self.__observer.updateCycle(self.get_environment(), self)
-
-    def attach(self, observer: 'Controleur') -> None:
-        """
-        set observer pointer to observer
-        """
-        self.__observer = observer
diff --git a/pyAmakCore/classes/tools/loggable.py b/pyAmakCore/classes/tools/loggable.py
index 094e4f0ab9ce6789398d85a181a4872de0e8b58b..5ac77e22b2350d9b629a4ecce8ca0ed964fc5ec0 100644
--- a/pyAmakCore/classes/tools/loggable.py
+++ b/pyAmakCore/classes/tools/loggable.py
@@ -3,7 +3,6 @@ class allowing to save the state of the system at a given moment
 """
 from os import path
 from typing import List
-
 from pandas import DataFrame
 
 
diff --git a/pyAmakCore/classes/schedulable.py b/pyAmakCore/classes/tools/schedulable.py
similarity index 52%
rename from pyAmakCore/classes/schedulable.py
rename to pyAmakCore/classes/tools/schedulable.py
index 7cd78bd28568908727fb6e3b5c6b5d93502508b0..c594ba8d90814ad5dbb767db5b7bfb9eb93749a4 100644
--- a/pyAmakCore/classes/schedulable.py
+++ b/pyAmakCore/classes/tools/schedulable.py
@@ -1,10 +1,9 @@
 """
 Schedulable interface
 """
-from threading import Semaphore
 import sys
 import pathlib
-sys.path.insert(0, str(pathlib.Path(__file__).parent))
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
 
 from pyAmakCore.exception.override import ToOverrideWarning
 
@@ -13,7 +12,16 @@ class Schedulable:
     """
     Class Schedulable
     """
-    syncro_semaphore: Semaphore = Semaphore(0)
+
+    def __init__(self):
+
+        self.__nbr_cycle = 0
+
+    def get_cycle(self) -> int:
+        return self.__nbr_cycle
+
+    def cycle(self) -> None:
+        self.__nbr_cycle += 1
 
     def on_initialization(self) -> None:
         """
@@ -32,27 +40,3 @@ class Schedulable:
         This method will be executed at the end of each cycle
         """
         ToOverrideWarning("on_cycle_end")
-
-    def run(self) -> None:
-        """
-        Method that will be called by the thread
-        """
-        self.cycle()
-
-    def cycle(self) -> None:
-        """
-        Main behavior of the Schedulable
-        """
-        ToOverrideWarning("cycle")
-
-    def take_token_syncro(self) -> None:
-        """
-        Scheduler will wait here that the schedulable release a token
-        """
-        self.syncro_semaphore.acquire()
-
-    def give_token_syncro(self) -> None:
-        """
-        Unlock scheduler
-        """
-        self.syncro_semaphore.release()
diff --git a/pyAmakCore/classes/tools/schedulerIHM.py b/pyAmakCore/classes/tools/schedulerIHM.py
new file mode 100644
index 0000000000000000000000000000000000000000..9390671fd74934ee13020da1a0b4c51099fe6a76
--- /dev/null
+++ b/pyAmakCore/classes/tools/schedulerIHM.py
@@ -0,0 +1,32 @@
+"""
+Scheduler class that need to be used for pyAmakIhm
+"""
+import pathlib
+from time import sleep
+
+import sys
+
+sys.path.insert(0, str(pathlib.Path(__file__).parent.parent))
+
+from pyAmakCore.classes.amas import Amas
+from pyAmakCore.classes.scheduler import Scheduler
+
+
+class SchedulerIHM(Scheduler):
+    """
+    Convenient class to override while using pyAmakIHM
+    """
+
+    def __init__(self, amas: Amas):
+        self.__observer = None
+        super().__init__(amas)
+
+    def last_part(self) -> None:
+        super().last_part()
+        self.__observer.updateCycle()
+
+    def attach(self, observer: 'Controleur') -> None:
+        """
+        set observer pointer to observer
+        """
+        self.__observer = observer
diff --git a/pyAmakCore/tests/memory_leak/main.py b/pyAmakCore/tests/memory_leak/main.py
index 189fad630707dcfbb9f06245fb3368bceadd0324..a1a804ff4b60c888679878d63c78422a05d2768f 100644
--- a/pyAmakCore/tests/memory_leak/main.py
+++ b/pyAmakCore/tests/memory_leak/main.py
@@ -1,38 +1,39 @@
+from pyAmakCore.exception.override import ToOverrideWarning
+from pyAmakCore.classes.agent import Agent
 from pyAmakCore.classes.amas import Amas
 from pyAmakCore.classes.environment import Environment
-from pyAmakCore.classes.agent import Agent
+from pyAmakCore.classes.scheduler import Scheduler
 
 
 class SimpleAgent(Agent):
-    """
-    test
-    """
+    pass
 
 
 class SimpleAmas(Amas):
-    """
-    test
-    """
+    def on_initialization(self) -> None:
+        self.set_do_log(True)
 
     def on_initial_agents_creation(self) -> None:
         for i in range(10):
-            self.add_agent(Agent(self))
-
+            self.add_agent(SimpleAgent(self))
 
 class SimpleEnv(Environment):
-    """
-    test
-    """
+    pass
 
+import time
+start_time = time.time()
+ToOverrideWarning.enable_warning(False)
 
 env = SimpleEnv()
 amas = SimpleAmas(env)
 
-amas.put_token()
+scheduler = Scheduler(amas)
 
-amas.start()
+scheduler.start()
+scheduler.run()
+print("--- %s seconds ---" % (time.time() - start_time))
 
 
 """
 There are no visible memory leak in pyAmakCore
-"""
\ No newline at end of file
+"""
diff --git a/pyAmakCore/tests/test_agent/test_get_most_critical_neighbor.py b/pyAmakCore/tests/test_agent/test_get_most_critical_neighbor.py
index 4dff5c44a84625b18c6826c1d0b88cd9a21b2a2c..c190a4a6be87f19a87bacd81998dcb1368adcd99 100644
--- a/pyAmakCore/tests/test_agent/test_get_most_critical_neighbor.py
+++ b/pyAmakCore/tests/test_agent/test_get_most_critical_neighbor.py
@@ -11,9 +11,6 @@ class SimpleAgent(Agent):
     def set_criticality(self, i):
         self._Agent__criticality = i
 
-    def get_most_critical(self, i):
-        return self._get_most_critical_neighbor(i)
-
 
 class TestAgentGetMostCriticalNeighbor(TestCase):
     """
@@ -44,7 +41,7 @@ class TestAgentGetMostCriticalNeighbor(TestCase):
         n4.set_criticality(25)
         agent.add_neighbour(n4)
 
-        self.assertEqual(agent.get_most_critical(False), n4)
+        self.assertEqual(agent.get_most_critical_neighbor(False), n4)
 
     def test_get_most_critical_neighbor_with_self(self):
         Agent.reset_agent()
@@ -70,7 +67,7 @@ class TestAgentGetMostCriticalNeighbor(TestCase):
         n4.set_criticality(25)
         agent.add_neighbour(n4)
 
-        self.assertEqual(agent.get_most_critical(True), agent)
+        self.assertEqual(agent.get_most_critical_neighbor(True), agent)
 
 
 if __name__ == '__main__':
diff --git a/pyAmakCore/tests/test_agent/test_run.py b/pyAmakCore/tests/test_agent/test_run.py
deleted file mode 100644
index 991cb562b9fa394cda7aff988ffaa8171da595e0..0000000000000000000000000000000000000000
--- a/pyAmakCore/tests/test_agent/test_run.py
+++ /dev/null
@@ -1,52 +0,0 @@
-"""
-test that run of Agent work as intended
-"""
-from unittest import TestCase, main
-
-from pyAmakCore.classes.agent import Agent
-from pyAmakCore.classes.amas import Amas
-from pyAmakCore.classes.environment import Environment
-from pyAmakCore.enumeration.agent_phase import Phase
-from pyAmakCore.enumeration.executionPolicy import ExecutionPolicy
-
-
-class TestAgentRun(TestCase):
-    """
-    Test class for Agent run
-    """
-
-    def test_run_one_phase(self):
-        """
-        test that run() work and return correct phase with 1 phase policy
-        """
-        Agent.reset_agent()
-        environment = Environment()
-        amas = Amas(environment)
-        amas.set_execution_policy(ExecutionPolicy.ONE_PHASE)
-
-        agent = Agent(amas)
-        self.assertEqual(agent.get_phase(), Phase.INITIALIZING)
-        agent.run()
-        self.assertEqual(agent.get_phase(), Phase.DECISION_AND_ACTION_DONE)
-        agent.run()
-        self.assertEqual(agent.get_phase(), Phase.DECISION_AND_ACTION_DONE)
-
-    def test_run_two_phase(self):
-        """
-        test that run() work and return correct phase with 2 phase policy
-        """
-        Agent.reset_agent()
-        environment = Environment()
-        amas = Amas(environment)
-        amas.set_execution_policy(ExecutionPolicy.TWO_PHASES)
-
-        agent = Agent(amas)
-        self.assertEqual(agent.get_phase(), Phase.INITIALIZING)
-        agent.run()
-        self.assertEqual(agent.get_phase(), Phase.PERCEPTION_DONE)
-        agent.run()
-        self.assertEqual(agent.get_phase(), Phase.DECISION_AND_ACTION_DONE)
-
-
-if __name__ == '__main__':
-    main()
diff --git a/pyAmakCore/tests/test_amas/test_agent.py b/pyAmakCore/tests/test_amas/test_agent.py
index e43150f67f56a23074c9a934c3f706401a997a83..b5a9b187db038f3165b0ee0a2baaac9a722c03a5 100644
--- a/pyAmakCore/tests/test_amas/test_agent.py
+++ b/pyAmakCore/tests/test_amas/test_agent.py
@@ -45,24 +45,24 @@ class TestAmasAgents(TestCase):
         agent3 = Agent(amas)
         # add 1 agent
         amas.add_agent(agent1)
-        amas.cycle()
+        amas.add_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1])
 
         # don't remove previous agent
         amas.add_agent(agent2)
-        amas.cycle()
+        amas.add_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent2])
 
         # add agent in good order
         amas.add_agent(agent3)
-        amas.cycle()
+        amas.add_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent2, agent3])
 
         # don't add duplicate
         amas.add_agent(agent1)
         amas.add_agent(agent2)
         amas.add_agent(agent3)
-        amas.cycle()
+        amas.add_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent2, agent3])
 
     def test_add_agents(self) -> None:
@@ -80,16 +80,16 @@ class TestAmasAgents(TestCase):
         agent5 = Agent(amas)
 
         amas.add_agents([agent1, agent2, agent3, agent4, agent5])
-        amas.cycle()
+        amas.add_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent2, agent3, agent4, agent5])
 
         amas = SimplerAmas(environment)
         amas.add_agents([agent1, agent2])
-        amas.cycle()
+        amas.add_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent2])
 
         amas.add_agents([agent1, agent2, agent4, agent2, agent3])
-        amas.cycle()
+        amas.add_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent2, agent4, agent3])
 
     def test_remove_agent(self) -> None:
@@ -101,22 +101,23 @@ class TestAmasAgents(TestCase):
         agent3 = Agent(amas)
 
         amas.remove_agent(agent2)
-        amas.cycle()
+        amas.remove_pending_agent()
         self.assertEqual(amas.get_agents(), [])
 
         amas.add_agents([agent1, agent2, agent3])
+        amas.add_pending_agent()
 
         amas.remove_agent(agent2)
-        amas.cycle()
+        amas.remove_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent3])
 
         amas.remove_agent(agent2)
-        amas.cycle()
+        amas.remove_pending_agent()
         self.assertEqual(amas.get_agents(), [agent1, agent3])
 
         amas.remove_agent(agent1)
         amas.remove_agent(agent3)
-        amas.cycle()
+        amas.remove_pending_agent()
         self.assertEqual(amas.get_agents(), [])
 
 
diff --git a/release/changelog.txt b/release/changelog.txt
index 06af3f7857489efc206e726f505ec486d4a3e29d..89ba2421f6a4473f248b68aaece5b509675c4337 100644
--- a/release/changelog.txt
+++ b/release/changelog.txt
@@ -1,3 +1,7 @@
+v0.1.0:
+ WARNING : all previous example will no longer work in this version, and all v0.1.0+ example won't work in previous version
+ * Way better thread management
+
 v0.0.5:
  * Fix rare bugs : an agent that would be removed in the cycle could be called by another agent
  * CSV : Add method : add_ignore_attribute(self, attribute: str) -> None, remove_ignore_attribute(self, attribute: str) -> None
diff --git a/setup.py b/setup.py
index c80c5a1fd15a52b50f6131c38cdf309c329b3c96..3d73d5dccd4434e871c2cf07eb5550230a49ab19 100644
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
 setup(
     name='pyAmakCore',
     packages=find_packages(),
-    version='0.0.5',
+    version='0.1.0',
     description='AmakFramework in python',
     author='BE',
     install_requires=[],