黑马程序员技术交流社区

标题: Thread和Runnable的区别 [打印本页]

作者: 夏萱    时间: 2016-7-14 11:23
标题: Thread和Runnable的区别
本帖最后由 夏萱 于 2016-7-14 11:24 编辑

如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
  1. package com.multithread.learning;
  2. /**
  3. *@functon 多线程学习,继承Thread,资源不能共享
  4. *@author 林炳文
  5. *@time 2015.3.9
  6. */
  7. class Thread1 extends Thread{
  8.         private int count=5;
  9.         private String name;
  10.     public Thread1(String name) {
  11.        this.name=name;
  12.     }
  13.         public void run() {
  14.         for (int i = 0; i < 5; i++) {
  15.             System.out.println(name + "运行  count= " + count--);
  16.             try {
  17.                 sleep((int) Math.random() * 10);
  18.             } catch (InterruptedException e) {
  19.                 e.printStackTrace();
  20.             }
  21.         }
  22.       
  23.         }
  24. }

  25. public class Main {

  26.         public static void main(String[] args) {
  27.                 Thread1 mTh1=new Thread1("A");
  28.                 Thread1 mTh2=new Thread1("B");
  29.                 mTh1.start();
  30.                 mTh2.start();

  31.         }

  32. }
复制代码


输出:

B运行  count= 5
A运行  count= 5
B运行  count= 4
B运行  count= 3
B运行  count= 2
B运行  count= 1
A运行  count= 4
A运行  count= 3
A运行  count= 2
A运行  count= 1

从上面可以看出,不同的线程之间count是不同的,这对于卖票系统来说就会有很大的问题,当然,这里可以用同步来作。这里我们用Runnable来做下看看


  1. /**
  2. *@functon 多线程学习 继承runnable,资源能共享
  3. *@author 林炳文
  4. *@time 2015.3.9
  5. */
  6. package com.multithread.runnable;
  7. class Thread2 implements Runnable{
  8.     private int count=15;
  9.         @Override
  10.         public void run() {
  11.                   for (int i = 0; i < 5; i++) {
  12.                           System.out.println(Thread.currentThread().getName() + "运行  count= " + count--);
  13.                     try {
  14.                             Thread.sleep((int) Math.random() * 10);
  15.                     } catch (InterruptedException e) {
  16.                         e.printStackTrace();
  17.                     }
  18.                 }
  19.                
  20.         }
  21.         
  22. }
  23. public class Main {

  24.         public static void main(String[] args) {
  25.                
  26.                 Thread2 my = new Thread2();
  27.                 new Thread(my, "C").start();//同一个mt,但是在Thread中就不可以,如果用同一个实例化对象mt,就会出现异常   
  28.                 new Thread(my, "D").start();
  29.                 new Thread(my, "E").start();
  30.         }

  31. }
复制代码


输出:

C运行  count= 15
D运行  count= 14
E运行  count= 13
D运行  count= 12
D运行  count= 10
D运行  count= 9
D运行  count= 8
C运行  count= 11
E运行  count= 12
C运行  count= 7
E运行  count= 6
C运行  count= 5
E运行  count= 4
C运行  count= 3
E运行  count= 2

这里要注意每个线程都是用同一个实例化对象,如果不是同一个,效果就和上面的一样了!


总结:

实现Runnable接口比继承Thread类所具有的优势:

1):适合多个相同的程序代码的线程去处理同一个资源

2):可以避免java中的单继承的限制

3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立




提醒一下大家:main方法其实也是一个线程。在java中所以的线程都是同时启动的,至于什么时候,哪个先执行,完全看谁先得到CPU的资源。


在java中,每次程序运行至少启动2个线程。一个是main线程,一个是垃圾收集线程。因为每当使用java命令执行一个类的时候,实际上都会启动一个JVM,每一个jVM实习在就是在操作系统中启动了一个进程。

四、线程状态转换



1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
3、运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
4、阻塞状态(Blocked):阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(一)、等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
(二)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
(三)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5、死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka

作者: ylca    时间: 2016-7-14 16:00
理论知识最好是言简意赅 不然不好背




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2