本帖最后由 夏萱 于 2016-7-14 11:24 编辑
如果一个类继承Thread,则不适合资源共享。但是如果实现了Runable接口的话,则很容易的实现资源共享。
- package com.multithread.learning;
- /**
- *@functon 多线程学习,继承Thread,资源不能共享
- *@author 林炳文
- *@time 2015.3.9
- */
- class Thread1 extends Thread{
- private int count=5;
- private String name;
- public Thread1(String name) {
- this.name=name;
- }
- public void run() {
- for (int i = 0; i < 5; i++) {
- System.out.println(name + "运行 count= " + count--);
- try {
- sleep((int) Math.random() * 10);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- }
- }
- public class Main {
- public static void main(String[] args) {
- Thread1 mTh1=new Thread1("A");
- Thread1 mTh2=new Thread1("B");
- mTh1.start();
- mTh2.start();
- }
- }
复制代码
输出:
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来做下看看
- /**
- *@functon 多线程学习 继承runnable,资源能共享
- *@author 林炳文
- *@time 2015.3.9
- */
- package com.multithread.runnable;
- class Thread2 implements Runnable{
- private int count=15;
- @Override
- public void run() {
- for (int i = 0; i < 5; i++) {
- System.out.println(Thread.currentThread().getName() + "运行 count= " + count--);
- try {
- Thread.sleep((int) Math.random() * 10);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- }
-
- }
- public class Main {
- public static void main(String[] args) {
-
- Thread2 my = new Thread2();
- new Thread(my, "C").start();//同一个mt,但是在Thread中就不可以,如果用同一个实例化对象mt,就会出现异常
- new Thread(my, "D").start();
- new Thread(my, "E").start();
- }
- }
复制代码
输出:
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
|