- join线程
Thread提供了让一个线程等待另一个线程完成的方法——join()方法。当在某个程序执行流中调用其它线程的join()方法时,调用线程将被阻塞,直到被join()方法加入的join线程执行完为止。
join()方法通常由使用线程的程序调用,以将大问题划分为许多小问题,每个小问题分配一个线程。当所有的小问题都得到处理后,再调用主线程来进一步操作。
1 2 public class JoinThread extends Thread { 3 4 /** 5 * @param args 6 */ 7 public JoinThread(String name) 8 { 9 super (name); 10 } 11 public void run() 12 { 13 for ( int i = 0 ; i < 100 ; i ++ ) 14 { 15 System.out.println(getName() + " " + i ); 16 } 17 } 18 public static void main(String[] args) throws Exception { 19 // TODO Auto-generated method stub 20 JoinThread jtt = new JoinThread( " 新线程 " ); 21 jtt.start(); 22 jtt.join(); 23 for ( int i = 0 ;i < 100 ; i ++ ) 24 { 25 if ( i == 20 ) 26 { 27 JoinThread jt = new JoinThread( " 被join的线程 " ); 28 jt.start(); 29 jt.join(); 30 } 31 System.out.println(Thread.currentThread().getName() + " " + i); 32 } 33 34 } 35 36 }
结果:
1 新线程 0 2 新线程 1 3 新线程 2 4 新线程 3 5 新线程 4 6 新线程 5 7 新线程 6 8 新线程 7 9 新线程 8 10 新线程 9 11 新线程 10 12 新线程 11 13 新线程 12 14 新线程 13 15 新线程 14 16 新线程 15 17 新线程 16 18 新线程 17 19 新线程 18 20 新线程 19 21 新线程 20 22 新线程 21 23 新线程 22 24 新线程 23 25 新线程 24 26 新线程 25 27 新线程 26 28 新线程 27 29 新线程 28 30 新线程 29 31 新线程 30 32 新线程 31 33 新线程 32 34 新线程 33 35 新线程 34 36 新线程 35 37 新线程 36 38 新线程 37 39 新线程 38 40 新线程 39 41 新线程 40 42 新线程 41 43 新线程 42 44 新线程 43 45 新线程 44 46 新线程 45 47 新线程 46 48 新线程 47 49 新线程 48 50 新线程 49 51 新线程 50 52 新线程 51 53 新线程 52 54 新线程 53 55 新线程 54 56 新线程 55 57 新线程 56 58 新线程 57 59 新线程 58 60 新线程 59 61 新线程 60 62 新线程 61 63 新线程 62 64 新线程 63 65 新线程 64 66 新线程 65 67 新线程 66 68 新线程 67 69 新线程 68 70 新线程 69 71 新线程 70 72 新线程 71 73 新线程 72 74 新线程 73 75 新线程 74 76 新线程 75 77 新线程 76 78 新线程 77 79 新线程 78 80 新线程 79 81 新线程 80 82 新线程 81 83 新线程 82 84 新线程 83 85 新线程 84 86 新线程 85 87 新线程 86 88 新线程 87 89 新线程 88 90 新线程 89 91 新线程 90 92 新线程 91 93 新线程 92 94 新线程 93 95 新线程 94 96 新线程 95 97 新线程 96 98 新线程 97 99 新线程 98 100 新线程 99 101 main 0 102 main 1 103 main 2 104 main 3 105 main 4 106 main 5 107 main 6 108 main 7 109 main 8 110 main 9 111 main 10 112 main 11 113 main 12 114 main 13 115 main 14 116 main 15 117 main 16 118 main 17 119 main 18 120 main 19 121 被join的线程 0 122 被join的线程 1 123 被join的线程 2 124 被join的线程 3 125 被join的线程 4 126 被join的线程 5 127 被join的线程 6 128 被join的线程 7 129 被join的线程 8 130 被join的线程 9 131 被join的线程 10 132 被join的线程 11 133 被join的线程 12 134 被join的线程 13 135 被join的线程 14 136 被join的线程 15 137 被join的线程 16 138 被join的线程 17 139 被join的线程 18 140 被join的线程 19 141 被join的线程 20 142 被join的线程 21 143 被join的线程 22 144 被join的线程 23 145 被join的线程 24 146 被join的线程 25 147 被join的线程 26 148 被join的线程 27 149 被join的线程 28 150 被join的线程 29 151 被join的线程 30 152 被join的线程 31 153 被join的线程 32 154 被join的线程 33 155 被join的线程 34 156 被join的线程 35 157 被join的线程 36 158 被join的线程 37 159 被join的线程 38 160 被join的线程 39 161 被join的线程 40 162 被join的线程 41 163 被join的线程 42 164 被join的线程 43 165 被join的线程 44 166 被join的线程 45 167 被join的线程 46 168 被join的线程 47 169 被join的线程 48 170 被join的线程 49 171 被join的线程 50 172 被join的线程 51 173 被join的线程 52 174 被join的线程 53 175 被join的线程 54 176 被join的线程 55 177 被join的线程 56 178 被join的线程 57 179 被join的线程 58 180 被join的线程 59 181 被join的线程 60 182 被join的线程 61 183 被join的线程 62 184 被join的线程 63 185 被join的线程 64 186 被join的线程 65 187 被join的线程 66 188 被join的线程 67 189 被join的线程 68 190 被join的线程 69 191 被join的线程 70 192 被join的线程 71 193 被join的线程 72 194 被join的线程 73 195 被join的线程 74 196 被join的线程 75 197 被join的线程 76 198 被join的线程 77 199 被join的线程 78 200 被join的线程 79 201 被join的线程 80 202 被join的线程 81 203 被join的线程 82 204 被join的线程 83 205 被join的线程 84 206 被join的线程 85 207 被join的线程 86 208 被join的线程 87 209 被join的线程 88 210 被join的线程 89 211 被join的线程 90 212 被join的线程 91 213 被join的线程 92 214 被join的线程 93 215 被join的线程 94 216 被join的线程 95 217 被join的线程 96 218 被join的线程 97 219 被join的线程 98 220 被join的线程 99 221 main 20 222 main 21 223 main 22 224 main 23 225 main 24 226 main 25 227 main 26 228 main 27 229 main 28 230 main 29 231 main 30 232 main 31 233 main 32 234 main 33 235 main 34 236 main 35 237 main 36 238 main 37 239 main 38 240 main 39 241 main 40 242 main 41 243 main 42 244 main 43 245 main 44 246 main 45 247 main 46 248 main 47 249 main 48 250 main 49 251 main 50 252 main 51 253 main 52 254 main 53 255 main 54 256 main 55 257 main 56 258 main 57 259 main 58 260 main 59 261 main 60 262 main 61 263 main 62 264 main 63 265 main 64 266 main 65 267 main 66 268 main 67 269 main 68 270 main 69 271 main 70 272 main 71 273 main 72 274 main 73 275 main 74 276 main 75 277 main 76 278 main 77 279 main 78 280 main 79 281 main 80 282 main 81 283 main 82 284 main 83 285 main 84 286 main 85 287 main 86 288 main 87 289 main 88 290 main 89 291 main 90 292 main 91 293 main 92 294 main 93 295 main 94 296 main 95 297 main 96 298 main 97 299 main 98 300 main 99 301
join()方法有如下3种重载方式。
- join():等待被join的线程执行完成。
- join(long millis):等待被join的线程的时间最长为millis毫秒。如果在millis毫秒内被join的线程还没有执行结束,则不再等待。
- join(long millis , int nanos):等待被join的线程的时间最长为millis毫秒加manos毫微秒。
- 后台线程
有一种线程,它是在后台运行的,它的任务是为其他的线程提供服务,这种线程被称为“后台线程(Daemon Thread)”,又称为“守护线程”或“精灵线程”。JVM的垃圾回收线程就是典型的后台线程。
后台线程有个特征:如果所有的前台线程都死亡,后台线程会自动死亡。
调用Thread对象的setDaemon(true)方法可将指定线程设置成后台线程。下面程序将执行线程设置成后台线程,可以看到当所有的前台线程死亡时,后台线程随之死亡。当整个虚拟机中只剩下后台线程时,程序就没有继续运行的必要了,所以虚拟机也就退出了。
1 2 public class DaemonThread extends Thread { 3 4 /** 5 * @param args 6 */ 7 public void run(){ 8 for ( int i = 0 ;i < 100 ; i ++ ){ 9 System.out.println(getName() + " " + i); 10 } 11 } 12 public static void main(String[] args) { 13 // TODO Auto-generated method stub 14 DaemonThread dt = new DaemonThread(); 15 dt.setDaemon( true ); 16 dt.start(); 17 for ( int i = 0 ; i < 10 ; i ++ ){ 18 System.out.println(Thread.currentThread().getName() + "" + i); 19 } 20 21 } 22 23 }
结果:
1 main0 2 Thread - 0 0 3 Thread - 0 1 4 Thread - 0 2 5 Thread - 0 3 6 main1 7 Thread - 0 4 8 Thread - 0 5 9 Thread - 0 6 10 Thread - 0 7 11 main2 12 Thread - 0 8 13 main3 14 Thread - 0 9 15 Thread - 0 10 16 Thread - 0 11 17 main4 18 Thread - 0 12 19 main5 20 Thread - 0 13 21 main6 22 Thread - 0 14 23 main7 24 Thread - 0 15 25 main8 26 Thread - 0 16 27 main9 28 Thread - 0 17 29 Thread - 0 18 30 Thread - 0 19 31 Thread - 0 20 32 Thread - 0 21 33 Thread - 0 22 34 Thread - 0 23 35 Thread - 0 24 36 Thread - 0 25 37 Thread - 0 26 38 Thread - 0 27 39 Thread - 0 28 40 Thread - 0 29 41 Thread - 0 30 42 Thread - 0 31 43 Thread - 0 32 44 Thread - 0 33 45 Thread - 0 34 46 Thread - 0 35 47
本来该线程应该执行到i = 99时才会结束,但运行程序时不难发现该后台线程无法运行到99,因为当主线程也就是程序中唯一的前台线程运行结束后,JVM会自动退出,因而后台线程也就被结束了。
- 线程睡眠:sleep
如果需要让当前正在执行的线程暂停一段时间,并进入阻塞状态,则可以通过调用Thread类的静态sleep()方法来实现。
当当前线程调用sleep()方法进入阻塞状态时,在其睡眠时间段内,该线程不会获得执行的机会,即使系统中没有其他可执行的线程,处于sleep()中的线程也不会执行,因此sleep()方法常用来暂停程序的执行。
下面程序调用sleep()方法来暂停主线程的执行,因为该程序只有一个主线程,当主线程进入睡眠后,系统没有可执行的线程,所以可以看到程序在sleep()方法处暂停。
1 import java.util.Date; 2 3 4 public class SleepTest { 5 6 /** 7 * @param args 8 * @throws InterruptedException 9 */ 10 public static void main(String[] args) throws InterruptedException { 11 // TODO Auto-generated method stub 12 for ( int i = 0 ;i < 10 ; i ++ ) 13 { 14 System.out.println( " 当前世界: " + new Date()); 15 Thread.sleep( 1000 ); 16 } 17 18 } 19 20 }
结果:
1 当前时间:Wed Nov 23 16 : 04 : 35 CST 2016 2 当前时间:Wed Nov 23 16 : 04 : 36 CST 2016 3 当前时间:Wed Nov 23 16 : 04 : 37 CST 2016 4 当前时间:Wed Nov 23 16 : 04 : 38 CST 2016 5 当前时间:Wed Nov 23 16 : 04 : 39 CST 2016 6 当前时间:Wed Nov 23 16 : 04 : 40 CST 2016 7 当前时间:Wed Nov 23 16 : 04 : 41 CST 2016 8 当前时间:Wed Nov 23 16 : 04 : 42 CST 2016 9 当前时间:Wed Nov 23 16 : 04 : 43 CST 2016 10 当前时间:Wed Nov 23 16 : 04 : 44 CST 2016
运行上面程序,看到程序依次输出10条字符串,输出2条字符串之间的时间间隔为1秒。
- 线程让步:yield
yield()方法是一个和sleep()方法有点相似的方法,它也是Thread类提供的一个静态方法,它也可以让当前正在执行的线程暂停,但它不会阻塞该线程,它只是将该线程转入就绪状态。yield()只是让当前线程暂停一下,让系统的线程调度器重新调度一次,完全可能的情况是:当某个线程调用了yield()方式暂停之后,线程调度器又将其调度出来重新执行。
实际上,当某个线程调用了yield()方法暂停之后,只有优先级与当前线程相同,或者优先级比以前线程更高的处于就绪状态的线程才会获得执行的机会。下面程序使用yield()方法来让当前正在执行的线程暂停。
1 public class YieldTest extends Thread { 2 public YieldTest(String name) { 3 super (name); 4 } 5 6 public void run() { 7 for ( int i = 0 ; i < 50 ; i ++ ) { 8 System.out.println(getName() + " " + i); 9 if (i == 20 ) { 10 Thread.yield(); 11 } 12 } 13 } 14 15 public static void main(String[] args) { 16 YieldTest yt1 = new YieldTest( " 高级 " ); 17 // yt1.setPriority(MAX_PRIORITY); 18 yt1.start(); 19 20 YieldTest yt2 = new YieldTest( " 低级 " ); 21 // yt2.setPriority(MIN_PRIORITY); 22 yt2.start(); 23 } 24 25 }
- 改变线程优先级
每个线程执行时都具有一定的优先级,优先级高的线程获得较多的执行机会,而低优先级的线程则获得较少的执行机会。
每个线程默认的优先级都与创建它的父线程的优先级相同,在默认情况下,main线程具有普通优先级,有main线程创建的子线程也具有普通优先级。
Thread类提供了setPriority(int new priority)、getPriority()方法来设置和返回指定线程的优先级,其中setPriority()方法的参数可以是一个整数,范围是1~10之间,也可以使用Thread类的如下3个静态常量。