多线程概念及多线程三种创建方式

多线程概念及多线程三种创建方式

  • 多线程相关概念
  • 创建线程方式1:继承Thread类,重写run(),调用start()开启线程
  • 创建线程方式2:实现Runnable接口,重写run(),执行线程需要丢给Runnable接口实现类(Thread类实现了Runnable),调用start开启线程
  • 继承Thread和实现Runable对比
  • 创建线程方式3:实现Callable接口,带返回值的

多线程相关概念

  • 线程就是独立的执行路径
  • 程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程、gc线程
  • main()称之为主线程,为系统的入口,用于执行整个程序
  • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统密切相关的,先后顺序不能人为干预
  • 对同一份资源进行操作时,会存在资源的抢夺问题,需要加入并发控制
  • 线程会带来额外的开销,如cpu调度时间,并发控制开销
  • 每个线程在自己的工作内存相互交互,内存控制不当会造成数据不一致

创建线程方式1:继承Thread类,重写run(),调用start()开启线程

线程不一定立即执行,cpu安排调度

package testthread;

//创建线程方式1:继承Thread类,重写run(),调用start()开启线程
public class Thread1 extends Thread {

    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 15; i++) {
            System.out.println("run方法体" + i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //main线程,也叫主线程

        //创建线程对象
        Thread1 thread1 = new Thread1();
        //调用start()开启线程
        thread1.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("main线程" + i);
            //休眠一下,便于观察
            Thread.sleep(50);
        }

        /** cpu调用是乱序交替执行的,每次输出结果都不一样,线程不一定立即执行,cpu安排调度
         main线程0
         run方法体0
         run方法体1
         run方法体2
         run方法体3
         run方法体4
         run方法体5
         run方法体6
         run方法体7
         run方法体8
         run方法体9
         run方法体10
         run方法体11
         run方法体12
         run方法体13
         run方法体14
         main线程1
         main线程2
         main线程3
         main线程4
         main线程5
         main线程6
         main线程7
         main线程8
         main线程9
         main线程10
         main线程11
         main线程12
         main线程13
         main线程14
         main线程15
         main线程16
         main线程17
         main线程18
         main线程19
         */
    }
}

html解析图片url,并用继承Thread类的多线程下载

创建线程方式2:实现Runnable接口,重写run(),执行线程需要丢给Runnable接口实现类(Thread类实现了Runnable),调用start开启线程

好处就是,继承是单继承,实现可以有多个实现

package testthread;

//创建线程方式2:实现Runnable接口,重写run(),执行线程需要丢给Runnable接口实现类(Thread类实现了Runnable),调用start开启线程
public class Thread2 implements Runnable {

    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 15; i++) {
            System.out.println("run方法体" + i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //main线程,也叫主线程

        //创建线程对象,通过线程对象来启动线程,代理
        Thread2 thread2 = new Thread2();
        Thread thread = new Thread(thread2);

        //调用start()开启线程
        thread.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("main线程" + i);
            //休眠一下,便于观察
            Thread.sleep(50);
        }

        /** cpu调用是乱序交替执行的
         main线程0
         run方法体0
         run方法体1
         run方法体2
         run方法体3
         run方法体4
         run方法体5
         run方法体6
         run方法体7
         run方法体8
         run方法体9
         run方法体10
         run方法体11
         run方法体12
         run方法体13
         run方法体14
         main线程1
         main线程2
         main线程3
         main线程4
         main线程5
         main线程6
         main线程7
         main线程8
         main线程9
         main线程10
         main线程11
         main线程12
         main线程13
         main线程14
         main线程15
         main线程16
         main线程17
         main线程18
         main线程19
         */
    }
}

继承Thread和实现Runable对比

继承Thread类
启动线程:子类对象.start()
不推荐使用:避免OOP单继承的局限性

实现Runable接口
启动线程:传入目标对象+Thread对象.start()
不推荐使用:避免OOP单继承的局限性,方便同一个对象被多个线程使用

创建线程方式3:实现Callable接口,带返回值的

  1. 实现Callable接口,需要返回值类型
  2. 重写call方法,需要抛出异常
  3. 创建目标对象
  4. 创建(开启)执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
  5. 提交执行:Future result1=ser.submit(t1);
  6. 获取结果:bollean r1=result1=result1.get();
  7. 关闭服务:ser.shutdownNow();
package testthread;

import org.apache.commons.io.FileUtils;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.tags.ImageTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.htmlparser.visitors.HtmlPage;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

//多线程同步下载图片
public class DownloadCallableThread implements Callable<String> {

    private String url;//网图地址
    private String fileName;//保存文件名

    public DownloadCallableThread(String url, String fileName) {
        this.url = url;
        this.fileName = fileName;
    }

    //线程执行体:下载图片
    @Override
    public String call() {
        Downloader downloader = new Downloader();
        downloader.downloader(url, fileName);
        System.out.println("下载文件名为" + fileName);
        return "下载文件名为" + fileName + "===下载文件时间" + System.currentTimeMillis();
    }

    public static NodeList parser(String url) throws ParserException {

        /**根据Url创建parser对象**/
        Parser parser = new Parser(url);

        /**设置编码,必须与Url编码一样 **/
        parser.setEncoding("utf-8");

        /** 构建一个Html页面对象 **/
        HtmlPage htmlPage = new HtmlPage(parser);
        parser.visitAllNodesWith(htmlPage);

        /** 获取Body下面所有的节点,可以想象成类似树状结构 **/
        NodeList list = htmlPage.getBody();

        /** 建立一个Filter,用于过滤节点,此处获得形如“”这样的节点 **/
        NodeFilter filter = new TagNameFilter("IMG");

        /** 得到过滤后的节点 **/
        list = list.extractAllNodesThatMatch(filter, true);

        for (int c = 0; c < list.size(); c++) {
            ImageTag imageTag = (ImageTag) list.elementAt(c);
            /** 输出图片的链接Url **/
            System.out.println(imageTag.getImageURL());
        }
        return list;
    }

    public static void main(String[] args) throws ParserException, ExecutionException, InterruptedException {
        NodeList list = DownloadThread1.parser("http://2t6y.mydown.com/yuanqidesktop/tianji.html?softid=585&tid1=256&tid2=1001&tod1=17111");
        System.out.println(list.size());
        //创建执行服务
        ExecutorService ser = Executors.newFixedThreadPool(list.size());

        DownloadCallableThread thread1 = new DownloadCallableThread(((ImageTag) list.elementAt(0)).getImageURL(), "1.png");
        DownloadCallableThread thread2 = new DownloadCallableThread(((ImageTag) list.elementAt(1)).getImageURL(), "2.png");
        DownloadCallableThread thread3 = new DownloadCallableThread(((ImageTag) list.elementAt(2)).getImageURL(), "3.png");
        DownloadCallableThread thread4 = new DownloadCallableThread(((ImageTag) list.elementAt(3)).getImageURL(), "4.png");
        DownloadCallableThread thread5 = new DownloadCallableThread(((ImageTag) list.elementAt(4)).getImageURL(), "5.png");
        DownloadCallableThread thread6 = new DownloadCallableThread(((ImageTag) list.elementAt(5)).getImageURL(), "6.png");
        DownloadCallableThread thread7 = new DownloadCallableThread(((ImageTag) list.elementAt(6)).getImageURL(), "7.png");
        DownloadCallableThread thread8 = new DownloadCallableThread(((ImageTag) list.elementAt(7)).getImageURL(), "8.png");
        DownloadCallableThread thread9 = new DownloadCallableThread(((ImageTag) list.elementAt(8)).getImageURL(), "9.png");
        DownloadCallableThread thread10 = new DownloadCallableThread(((ImageTag) list.elementAt(9)).getImageURL(), "10.png");
        DownloadCallableThread thread11 = new DownloadCallableThread(((ImageTag) list.elementAt(10)).getImageURL(), "11.png");
        //提交执行
        Future<String> r1 = ser.submit(thread1);
        Future<String> r2 = ser.submit(thread2);
        Future<String> r3 = ser.submit(thread3);
        Future<String> r4 = ser.submit(thread4);
        Future<String> r5 = ser.submit(thread5);
        Future<String> r6 = ser.submit(thread6);
        Future<String> r7 = ser.submit(thread7);
        Future<String> r8 = ser.submit(thread8);
        Future<String> r9 = ser.submit(thread9);
        Future<String> r10 = ser.submit(thread10);
        Future<String> r11 = ser.submit(thread11);

        //获取结果
        String result1 = r1.get();
        String result2 = r2.get();
        String result3 = r3.get();
        String result4 = r4.get();
        String result5 = r5.get();
        String result6 = r6.get();
        String result7 = r7.get();
        String result8 = r8.get();
        String result9 = r9.get();
        String result10 = r10.get();
        String result11 = r11.get();
        System.out.println(result1);
        System.out.println(result2);
        System.out.println(result3);
        System.out.println(result4);
        System.out.println(result5);
        System.out.println(result6);
        System.out.println(result7);
        System.out.println(result8);
        System.out.println(result9);
        System.out.println(result10);
        System.out.println(result11);

        //关闭服务
        ser.shutdownNow();

        /*
        "C:\Program Files\Java\jdk1.8.0_271\bin\java.exe" "-javaagent:D:\Users\Kingsoft\IntelliJ IDEA 2021.1.3\lib\idea_rt.jar=53686:D:\Users\Kingsoft\IntelliJ IDEA 2021.1.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_271\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_271\jre\lib\rt.jar;D:\workspace\Tests\target\classes;D:\Users\maven01_202112011747\apache-maven-3.8.4\.m2\commons-io\commons-io\2.11.0\commons-io-2.11.0.jar;D:\Users\maven01_202112011747\apache-maven-3.8.4\.m2\org\htmlparser\htmlparser\2.1\htmlparser-2.1.jar;D:\Users\maven01_202112011747\apache-maven-3.8.4\.m2\org\htmlparser\htmllexer\2.1\htmllexer-2.1.jar" testthread.DownloadCallableThread
https://dh1.cmcmcdn.com/sem/4/2/b/e/b/42bebba6bfd923aefede0b56d170013d.png
https://img-baofun.zhhainiao.com/market/semvideo/b8c4da367a3c730ca2c2e1eacf422107_preview.jpg
https://img-baofun.zhhainiao.com/market/238/F567AC46D63B85D2AA7E62AD01CD3692_preview.jpg
https://img-baofun.zhhainiao.com/market/238/b9c0ae90409426a9965e7247f9953658_preview.jpg
https://img-baofun.zhhainiao.com/market/238/c4302c9a3921d2f88b1322dc6173915d_preview.jpg
https://img-baofun.zhhainiao.com/market/238/9520e3c1f3b87509042affff4f446fe7_preview.jpg
https://img-baofun.zhhainiao.com/market/238/357E3204B3996B03966EE8116D229DF9_preview.jpg
https://img-baofun.zhhainiao.com/market/39/b25a301ef486487eb7992f1e81bd48d6_preview.jpg
https://img-baofun.zhhainiao.com/market/238/b9c0ae90409426a9965e7247f9953658_preview.jpg
https://img-baofun.zhhainiao.com/market/238/c4302c9a3921d2f88b1322dc6173915d_preview.jpg
https://img-baofun.zhhainiao.com/market/238/9520e3c1f3b87509042affff4f446fe7_preview.jpg
https://img-baofun.zhhainiao.com/market/238/357E3204B3996B03966EE8116D229DF9_preview.jpg
https://img-baofun.zhhainiao.com/market/39/b25a301ef486487eb7992f1e81bd48d6_preview.jpg
https://img-baofun.zhhainiao.com/market/semvideo/b8c4da367a3c730ca2c2e1eacf422107_preview.jpg
https://img-baofun.zhhainiao.com/market/238/F567AC46D63B85D2AA7E62AD01CD3692_preview.jpg
https://img-baofun.zhhainiao.com/market/238/F567AC46D63B85D2AA7E62AD01CD3692_preview.jpg
https://img-baofun.zhhainiao.com/market/238/b9c0ae90409426a9965e7247f9953658_preview.jpg
https://img-baofun.zhhainiao.com/market/238/c4302c9a3921d2f88b1322dc6173915d_preview.jpg
https://img-baofun.zhhainiao.com/market/238/9520e3c1f3b87509042affff4f446fe7_preview.jpg
https://img-baofun.zhhainiao.com/market/238/357E3204B3996B03966EE8116D229DF9_preview.jpg
https://img-baofun.zhhainiao.com/market/39/b25a301ef486487eb7992f1e81bd48d6_preview.jpg
https://img-baofun.zhhainiao.com/market/semvideo/b8c4da367a3c730ca2c2e1eacf422107_preview.jpg









31
下载文件名为1.png
下载文件名为5.png
下载文件名为10.png
下载文件名为8.png
下载文件名为4.png
下载文件名为7.png
下载文件名为11.png
下载文件名为6.png
下载文件名为3.png
下载文件名为2.png
下载文件名为9.png
下载文件名为1.png===下载文件时间1644226672406
下载文件名为2.png===下载文件时间1644226674753
下载文件名为3.png===下载文件时间1644226674467
下载文件名为4.png===下载文件时间1644226673734
下载文件名为5.png===下载文件时间1644226672985
下载文件名为6.png===下载文件时间1644226674311
下载文件名为7.png===下载文件时间1644226674035
下载文件名为8.png===下载文件时间1644226673623
下载文件名为9.png===下载文件时间1644226674771
下载文件名为10.png===下载文件时间1644226673090
下载文件名为11.png===下载文件时间1644226674060

Process finished with exit code 0

         */
    }
}

//下载器
class Downloader2 {
    //下载方法
    public void downloader(String url, String fileName) {
        //拷贝url地址到文件
        try {
            FileUtils.copyURLToFile(new URL(url), new File(fileName));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,Downloader方法异常");
        }
    }
}

你可能感兴趣的:(并发编程,java,多线程)