不知道大家学习或者使用线程时有没有思考过什么是线程?
大多数书上或者文章上都是这么解释的:线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。
这时候有没有产生第二个疑问:那么如何创建一个线程呢?
咱继续引经据典:1.利用Thread类的子类来创建线程2.利用Runnable接口来创建线程
此刻我的理解告诉我一个类继承Thread或者实现Runnable就算是一个线程了。但其实这样的理解会坑了自己。
比如我在思考线程池问题时就掉坑了,那既然无论是继承Thread还是实现Runnable都是线程,又说线程是独立的,那为何池中的线程还可以继续用呢?(第三个问题)
这个问题我开始不得其解,开始看书查资料
看到这篇关于讲解线程池原理的文章时我稍微了解了点http://blog.csdn.net/hsuxu/article/details/8985931
然后继续看了Thread和Runnable的源码时又明白了点。
public class Thread implements Runnable{ //此处只粘贴局部代码 /* What will be run. */ private Runnable target; @Override public void run() { if (target != null) { target.run(); } } }
注意Thread 实现了Runnable,Thread 覆写run()中是用的target.run();
现在让我们再写2种实现线程方式的代码
public class ThreadTest1 extends Thread{ @Override public void run() { for(int i = 0;i<10;i++){ System.out.println(i); try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { new ThreadTest1().start(); } }
public class RunnableTest1 implements Runnable{ @Override public void run() { for(int i = 0;i<10;i++){ System.out.println(i); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { Thread thread = new Thread(new RunnableTest1()); thread.start(); } }
继承了Thread的类用的是new ThreadTest1().start();
实现了Runnable的类用的是Thread thread = new Thread(new RunnableTest1()); thread.start();
也就是说,要启动一个线程就要调用Thread类(或者他的子类)的start()方法!
那么start()之后干了什么呢?
start()之后就是等待cpu资源然后运行run()。
此处高能预警
继承了Thread的类在启动时是真的启动了一个新的线程,而实现了Runnable的类(我感觉实现了Runnable的类应该说是定义了线程执行的任务类比叫他线程类更合适)是通过将他的实例放到一个Thread实例中来启动的
也就是设置了Thread中的
private Runnable target;
也就是说这个Thread可以放Runnable的A的实例也可以放Runnable的B的实例。这里差不多可以思考到我一个线程可以执行不同的任务!
但是真的可以在运行时修改线程中的private Runnable target;吗?答案我还不清楚。。。
不过呢,上面链接的文章给出了一个实现的方法
通过定义一个工作线程来实现,具体的看如下代码
private class WorkThread extends Thread { // 该工作线程是否有效,用于结束该工作线程 private boolean isRunning = true; /* * 关键所在啊,如果任务队列不空,则取出任务执行,若任务队列空,则等待 */ @Override public void run() { Runnable r = null; while (isRunning) {// 注意,若线程无效则自然结束run方法,该线程就没用了 synchronized (taskQueue) { while (isRunning && taskQueue.isEmpty()) {// 队列为空 try { taskQueue.wait(20); } catch (InterruptedException e) { e.printStackTrace(); } } if (!taskQueue.isEmpty()) r = taskQueue.remove(0);// 取出任务 } if (r != null) { r.run();// 执行任务 } finished_task++; r = null; } } // 停止工作,让该线程自然执行完run方法,自然结束 public void stopWorker() { isRunning = false; } }
他覆写了run()方法,在里面通过while循环和设置Runnable r = null; 的r的值来实现一个Thread执行不同的任务。这里我又产生了个疑问:可以不用Runnable 而随便用一个接口吗?比如,我定义一个Task接口
public interface Task { public abstract void doTask(); }
然后修改上面的WorkThread 类为
private class WorkThread extends Thread { // 该工作线程是否有效,用于结束该工作线程 private boolean isRunning = true; /* * 关键所在啊,如果任务队列不空,则取出任务执行,若任务队列空,则等待 */ @Override public void run() { Task t = null; while (isRunning) {// 注意,若线程无效则自然结束run方法,该线程就没用了 synchronized (taskQueue) { while (isRunning && taskQueue.isEmpty()) {// 队列为空 try { taskQueue.wait(20); } catch (InterruptedException e) { e.printStackTrace(); } } if (!taskQueue.isEmpty()) t = taskQueue.remove(0);// 取出任务 } if (t != null) { t.doTask();// 执行任务 } finished_task++; t = null; } } // 停止工作,让该线程自然执行完run方法,自然结束 public void stopWorker() { isRunning = false; } }
这样子不也一样吗?我暂时觉得没问题。。。我觉得之所以感觉Runnable和其他的不一样是因为Thread继承了Runnable,继而实现了run()方法,而线程启动后调用的就是这么个run方法从而显得Runnable与众不同。上面修改后的WorkThread在覆写run()方法时修改了真正执行的任务,那我觉得随便定义一个接口里面定义了运行的任务就好啦。
以上是今天对于线程池的小小的思考。