1919import  java .util .Collections ;
2020import  java .util .IdentityHashMap ;
2121import  java .util .Iterator ;
22+ import  java .util .LinkedList ;
2223import  java .util .List ;
2324import  java .util .Map ;
2425import  java .util .Map .Entry ;
2728import  java .util .concurrent .ConcurrentHashMap ;
2829
2930import  org .eclipse .core .runtime .Assert ;
31+ import  org .eclipse .core .runtime .IProgressMonitor ;
32+ import  org .eclipse .core .runtime .IStatus ;
33+ import  org .eclipse .core .runtime .Status ;
34+ import  org .eclipse .core .runtime .jobs .Job ;
3035
3136import  org .eclipse .jface .text .AbstractDocument ;
3237import  org .eclipse .jface .text .BadLocationException ;
4853 */ 
4954public  class  AnnotationModel  implements  IAnnotationModel , IAnnotationModelExtension , IAnnotationModelExtension2 , ISynchronizable  {
5055
56+ 	/** 
57+ 	 * This job is replacing the original thread, to make it multi thread safe (fixes the race 
58+ 	 * condition of fModelEvent) 
59+ 	 */ 
60+ 	private  final  class  FireModelChangeJob  extends  Job  {
61+ 
62+ 		private  LinkedList <AnnotationModelEvent > events = new  LinkedList <>();
63+ 
64+ 		private  FireModelChangeJob () {
65+ 			super (Messages .AnnotationModel_FireModelChangedEventJobTitle );
66+ 		}
67+ 
68+ 		@ Override 
69+ 		protected  IStatus  run (IProgressMonitor  monitor ) {
70+ 			synchronized  (events ) {
71+ 				AnnotationModelEvent  nextEvent = events .poll ();
72+ 				while  (nextEvent  != null ) {
73+ 					fireModelChanged (nextEvent );
74+ 					nextEvent = events .poll ();
75+ 				}
76+ 			}
77+ 			return  Status .OK_STATUS ;
78+ 		}
79+ 
80+ 		/** 
81+ 		 * Adds a new {@link AnnotationModelEvent} to the events list to fire it in the job 
82+ 		 * execution. If job is running 
83+ 		 * 
84+ 		 * @param event the event to fire. 
85+ 		 */ 
86+ 		public  void  fireDelayedModelChangedEvent (AnnotationModelEvent  event ) {
87+ 			if  (event  != null ) {
88+ 				synchronized  (events ) {
89+ 					events .add (event );
90+ 				}
91+ 				schedule ();
92+ 			}
93+ 		}
94+ 	}
5195
5296	/** 
5397	 * Iterator that returns the annotations for a given region. 
@@ -307,6 +351,12 @@ public void modelChanged(AnnotationModelEvent event) {
307351	 */ 
308352	private  Object  fModificationStamp = new  Object ();
309353
354+ 	/** 
355+ 	 * The job for firing the model changes 
356+ 	 * @since 3.14 
357+ 	 */ 
358+ 	private  FireModelChangeJob  modelChangedEventJob ;
359+ 
310360	/** 
311361	 * Creates a new annotation model. The annotation is empty, i.e. does not 
312362	 * manage any annotations and is not connected to any document. 
@@ -315,6 +365,7 @@ public AnnotationModel() {
315365		fAnnotations = new  AnnotationMap (10 );
316366		fPositions = new  IdentityHashMap <>(10 );
317367		fAnnotationModelListeners = new  ArrayList <>(2 );
368+ 		modelChangedEventJob  = new  FireModelChangeJob ();
318369
319370		fDocumentListener = new  IDocumentListener () {
320371
@@ -667,10 +718,10 @@ protected void cleanup(boolean fireModelChanged) {
667718	/** 
668719	 * Removes all annotations from the model whose associated positions have been 
669720	 * deleted. If requested inform all model listeners about the change. If requested 
670- 	 * a new thread  is created for the notification of the model listeners. 
721+ 	 * a new job  is created for the notification of the model listeners. 
671722	 * 
672723	 * @param fireModelChanged indicates whether to notify all model listeners 
673- 	 * @param forkNotification <code>true</code> iff  notification should be done in a new thread  
724+ 	 * @param forkNotification <code>true</code> if  notification should be done in a new job  
674725	 * @since 3.0 
675726	 */ 
676727	private  void  cleanup (boolean  fireModelChanged , boolean  forkNotification ) {
@@ -692,14 +743,7 @@ private void cleanup(boolean fireModelChanged, boolean forkNotification) {
692743			if  (fireModelChanged  && forkNotification ) {
693744				removeAnnotations (deleted , false , false );
694745				synchronized  (getLockObject ()) {
695- 					if  (fModelEvent  != null ) {
696- 						new  Thread () {
697- 							@ Override 
698- 							public  void  run () {
699- 								fireModelChanged ();
700- 							}
701- 						}.start ();
702- 					}
746+ 					modelChangedEventJob .fireDelayedModelChangedEvent (fModelEvent );
703747				}
704748			} else  {
705749				removeAnnotations (deleted , fireModelChanged , false );
0 commit comments