Java学习 之 多线程
1 /* 2 3 线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程,一个进程中是可以有多个线程的,这个应用程序称之为多线程 4 5 单线程:即有多个任务只能依次执行,当上个任务执行结束后,下个任务开始执行 6 7 多线程:即有多个任务可以同时执行 8 9 主线程:jvm启动后,必然有一个执行路径(线程)从main方法开始,一直执行到main方法结束,这个线程在java中称之为主线程 10 11 多线程:多线程执行时,在栈内存中,其实每一个执行线程都有一片自己所属的栈内存空间,进行方法的压栈和弹栈 12 13 */ 14 15 /* 16 17 Thread类: 18 19 构造方法:Thread()分配新的Thread对象 20 21 Thread(String name)分配新的Thread对象,将指定的name作为其线程名称 22 23 方法: void start()使线程开始执行,虚拟机调用该线程的run方法 24 25 void run()该线程要执行的操作 26 27 static void sleep(long millis)在指定的毫秒数内让当前正在执行的线程休眠 28 29 创建新执行线程的两种方法: 30 31 1、将类声明为Thread的子类,该子类重写Thread类的run方法,创建对象,开启线程,run方法相当于其他线程的main方法 32 33 2、声明一个实现Runnable接口的类,该类然后实现run方法,然后创建Runnable的子类对象,传入到某个线程的构造方法中,开启线程 34 35 */ 36 37 public class Demo1{ 38 39 public static void main(String[] args){ 40 41 //创建自定义线程对象 42 43 MyThread mt = new MyThread("新线程"); 44 45 //开启线程 46 47 mt.start(); 48 49 //在主方法中执行for循环 50 51 for(int i = 0 ; i < 10 ; i++){ 52 53 System.out.println("main线程" + i); 54 55 } 56 57 } 58 59 } 60 61 //自定义线程类 62 63 public class MyThread extends Thread{ 64 65 //定义指定线程名称的构造方法 66 67 public MyThread(String name){ 68 69 //调用父类的String参数的构造方法,指定线程的名称 70 71 super(name); 72 73 } 74 75 //重写run方法,完成该线程执行的逻辑 76 77 @Override 78 79 public void run(){ 80 81 for(int i = 0 ; i < 10 ; i++){ 82 83 System.out.println(getName() + "正在执行" + i); 84 } 85 86 } 87 88 } 89 90 /* 91 92 获取线程名称: 93 94 static Thread currentThread()返回对当前正在执行的线程对象的引用 95 96 String getName()返回该线程的名称 97 98 */ 99 100 public class MyThread extends Thread{ 101 102 //重写run方法 103 104 public void run(){ 105 106 for(int i = 0 ; i < 10 ; i++){ 107 108 System.out.println(Thread.currentThread().getName() +", i =" + i); 109 110 } 111 112 public MyThread(String name){ 113 114 super(name); 115 116 } 117 118 } 119 120 } 121 122 public class ThreadDemo{ 123 124 public staitc void main(String[] args){ 125 126 //创建两个线程任务 127 128 MyThread mt = new MyThread(); 129 130 MyThread mt2 = new MyThread(); 131 132 mt.run();//没有开启新线程,在主线程调用run方法 133 134 mt2.start();//开启一个新线程,新线程调用run方法 135 136 } 137 138 } 139 140 /* 141 142 实现Runnanle接口: 143 144 接口中的方法: void run()使用实现接口Runnable的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用对象的run方法 145 146 Thread类构造方法: 147 148 Thread(Runnable target)分配新的Thread对象,以便将target作为其运行对象 149 150 Thread(Runnable target , String name)分配新的Thread对象,以便将target作为其运行对象,将指定的name作为其名称 151 152 实现Runnable接口避免了单继承的局限性 153 154 */ 155 156 public class RunnableDemo{ 157 158 public static void main(String[] args){ 159 160 //创建线程执行目标类对象 161 162 Runnable run = new MyRunnable(); 163 164 //将Runnable接口的子类对象作为参数传递给Thread类的构造函数 165 166 Thread t = new Thread(run); 167 168 Thread t1 = new Thread(run); 169 //开启线程 170 171 t.start(); 172 173 t1.start(); 174 175 for(int i = 0 ; i < 10 ; i++){ 176 177 System.out.println("main线程:" + i); 178 179 } 180 181 } 182 183 } 184 185 //自定义线程执行任务类 186 187 public class MyRunnable implements Runnable{ 188 189 //定义线程要执行的run方法 190 191 @Override 192 193 public void run(){ 194 195 for(int i = 0 ; i < 10 ; i++){ 196 197 System.out.println("我的线程:" + i); 198 199 } 200 201 } 202 203 } 204 205 /* 206 207 线程的匿名内部类:使用线程的匿名内部类方式,可以方便的实现每个线程执行不同的线程任务操作 208 */ 209 210 new Thread(){ 211 212 public void run(){ 213 214 for(int i = 0 ; i < 10 ; i++){ 215 216 System.out.println(Thread.currentThread().getName() +" i :"+ i); 217 218 } 219 220 } 221 222 }.start(); 223 224 225 226 Runnable r = new Runnable(){ 227 228 public void run(){ 229 230 for(int i =0 ; i < 10 ; i++){ 231 232 System.out.println(Thread.currentThread().getName()); 233 234 } 235 236 } 237 238 }; 239 240 new Thread(r).start(); 241 242 /* 243 244 线程池:就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源 245 246 Executors:线程池创建工厂类 247 248 public static ExecutorService newFixedThreadPool(int nThread)返回线程池对象 249 250 ExecutorService:线程池类 251 252 Future<?> submit(Runnable task)获取线程池中的某个一个线程对象,并执行 253 254 Future接口:用来记录线程任务执行完毕后产生的结果,线程池创建与使用 255 256 */ 257 258 public class ThreadPoolDemo{ 259 260 public static void main(String[] args){ 261 262 //创建线程池对象 263 264 ExecutorService es = Executors.newFixedThreadPool(2);//包含2个线程对象 265 266 //创建Runnable实例对象 267 268 MyRunnable mr = new MyRunnable(); 269 270 //从线程池中获取线程对象,然后调用MyRunnable中的run() 271 272 es.submit(mr); 273 274 //再获取个线程对象,调用MyRunnable中的run() 275 276 es.submit(r); 277 278 es.submit(r); 279 280 //submit方法调用结束后,程序并不终止,因为线程池控制了线程的关闭,将使用完的线程又归还到了线程池中 281 282 //关闭线程池 283 284 es.shutdown(); 285 286 } 287 288 } 289 290 public class MyRunnable implements Runnable{ 291 292 @Override 293 294 public void run(){ 295 296 System.out.println("abc"); 297 298 try{ 299 300 Thread.sleep(2000); 301 302 }catch(Exception e){ 303 304 e.printStackTrace(); 305 306 } 307 308 System.out.println("a" +Thread.currentThread().getName()); 309 310 System.out.println("bc"); 311 } 312 313 } 314 315 /* 316 317 Callable接口:与Runnable接口功能相似,用来指定线程任务,其中call()方法,用来返回线程任务执行完毕后的结果,call方法可抛异常 318 319 ExecutorService:线程池类 320 <T>Future<T> submit(Callable<T> task)获取线程池中的某个一个线程对象,并执行线程中的call()方法 321 Future接口:用来记录线程任务执行完毕后产生的结果,线程池创建与使用 322 323 */ 324 325 public class ThreadPoolDemo{ 326 327 public static void main(String[] args){ 328 329 //创建线程池对象 330 331 ExecutorService es = Executors.newFixedThreadPool(2);//包含2个线程对象 332 333 //创建Runnable实例对象 334 335 MyCallable c = new MyCallable(); 336 337 //从线程池中获取线程对象,然后调用MyRunnable中的run() 338 339 es.submit(c); 340 341 //再获取个线程对象,调用MyCallable中的run() 342 343 es.submit(c); 344 345 es.submit(c); 346 347 //submit方法调用结束后,程序并不终止,因为线程池控制了线程的关闭,将使用完的线程又归还到了线程池中 348 349 //关闭线程池 350 351 es.shutdown(); 352 353 } 354 355 } 356 357 public class MyCallable implements Callable{ 358 359 @Override 360 361 public Object call() throws Exception{ 362 363 System.out.println("abc"); 364 365 Thread.sleep(2000); 366 367 System.out.println("a:" + Thread.currentThread().getName()); 368 System.out.println("bc"); 369 return null; 370 371 } 372 373 }