zoukankan      html  css  js  c++  java
  • 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()方法时修改了真正执行的任务,那我觉得随便定义一个接口里面定义了运行的任务就好啦。

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

  • 相关阅读:
    javascript:void(0) 和 href="#"的区别
    Subverion仓库迁移知识点整理
    EasyUI出现多条边框重合的问题
    EasyUI相关知识点整理
    EasyUI添加进度条
    yum配置文件中baseurl和mirrorlist的区别
    xshell中出现的绿色背景的文件夹
    Docker相关知识整理
    mysql 实验论证 innodb表级锁与行级锁
    MySQL索引优化实例说明
  • 原文地址:https://www.cnblogs.com/vincentren/p/6682403.html
Copyright © 2011-2022 走看看