java 多线程(一)

不知道大家学习或者使用线程时有没有思考过什么是线程?

大多数书上或者文章上都是这么解释的:线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派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 实现了RunnableThread 覆写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()方法时修改了真正执行的任务,那我觉得随便定义一个接口里面定义了运行的任务就好啦。

以上是今天对于线程池的小小的思考。

原文地址:https://www.cnblogs.com/vincentren/p/6682403.html