Java多线程——Day01

Java.Thread Day01

文章总结自B站狂神说JAVA

1.什么是多线程

一个程序同时进行多个相同或者不同的任务。一个人吃饭时拉屎(不要脑补)也是多线程。
Java中允许应用程序同时执行多个线程,每个线程都有优先权。

2.创建多线程

2.1 继承Thread类

新建一个类继承Thread类

public class ThreadDemo01 extends Thread {


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

在JAVA中多个线程开启后不一定会立即执行,由CPU调度执行。

public class ThreadDemo01 extends Thread {


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

    /**
     * main线曾
     * @param args
     */
    public static void main(String[] args) {

//        创建线程对象,调用start方法
        ThreadDemo01 thread = new ThreadDemo01();
        thread.start();

        for (int i = 0; i < 2000; i++) {
            System.out.println("main线程"+i);
        }
    }

}

上面的程序中,run线程不一定会调用start方法后立即执行,会根据cpu的调度执行。

idea生成for循环快捷键 xx.for会生成:

//xx必须为数字
  for (int i = 0; i < xx; i++) {
            
        }

下载网图demo:
下载commons io 的 jar包apache官网下载


/**
 * @date 2020/7/23 8:48
 * 实现多线程下载图片
 */
public class ThreadDemo02 extends Thread {

    private String url;
    private String fileName;

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

    @Override
    public void run() {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,fileName);
        System.out.println("下载文件"+fileName);
    }

    public static void main(String[] args) {
        ThreadDemo02 t1 = new ThreadDemo02("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595477956679&di=6086c0909a5a4499ab5784c42ea20183&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201901%2F17%2F20190117230425_eofqv.thumb.700_0.jpg","t1.jpg");
        ThreadDemo02 t2 = new ThreadDemo02("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595477956679&di=6086c0909a5a4499ab5784c42ea20183&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201901%2F17%2F20190117230425_eofqv.thumb.700_0.jpg","t2.jpg");
        ThreadDemo02 t3 = new ThreadDemo02("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595477956679&di=6086c0909a5a4499ab5784c42ea20183&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201901%2F17%2F20190117230425_eofqv.thumb.700_0.jpg","t3.jpg");

        t3.start();
        t2.start();
        t1.start();
    }

    class WebDownloader{
        public void downloader(String url,String fileName){
            try {
                FileUtils.copyURLToFile(new URL(url),new File(fileName));
            }catch (IOException e){
                e.printStackTrace();
                System.out.println("IO异常");
            }
        }
    }

}

这里运行顺序并不是根据调用start进程的顺序来运行的,而是根据CPU分配的。
在这里插入图片描述

2.2 实现Runnable接口


/**
 * @date 2020/7/23 9:40
 * 实现Runnable接口多线程
 */
public class ThreadDemo03 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 30; i++) {
            System.out.println("run线程运行ing..."+i);
        }
    }

    public static void main(String[] args) {

//        创建一个是实现了Runnable接口的对象实例
        ThreadDemo03 threadDemo03 = new ThreadDemo03();
//        创建一个Thread对象并且将实现了Runnable接口的实例对象传递进去。
        Thread thread = new Thread(threadDemo03);
//        使用Thread对象调用start方法。
        thread.start();

//        上面两行代码可以简写为:
        new Thread(threadDemo03).start();



        for (int i = 0; i < 3000; i++) {
            System.out.println("main线程运行ing..."+i);
        }
    }
}

使用Runnable接口来实现多线程,在调用时与使用Thread类实现多线程有不同。由于Java的单一继承机制,使用改接口就可以避免继承机制的局限性,方便一个对象被多个线程调用。
所以推荐使用实现Runnale接口来实现多线程。
多线程同时操作一个对象:

/**
 * @date 2020/7/23 9:40
 * 实现Runnable接口多线程,多个线程操作一个对象。
 */
public class ThreadDemo04 implements Runnable {

    private int ticketNums = 100;


    @Override
    public void run() {
       while (true){
           if (ticketNums < 0){
               break;
           }
           try {
               Thread.sleep(200);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println(Thread.currentThread().getName()+"抢到第"+ticketNums--+"票!!");
       }
    }

    public static void main(String[] args) {
        ThreadDemo04 threadDemo04 = new ThreadDemo04();
        new Thread(threadDemo04,"吴彦祖").start();
        new Thread(threadDemo04,"梁朝伟").start();
        new Thread(threadDemo04,"彭于晏").start();
    }
}

如果同时操作一个对象,线程不安全,数据紊乱。
比如:

梁朝伟抢到第49票!!
彭于晏抢到第49票!!
梁朝伟抢到第-1票!!
彭于晏抢到第-2票!!

这种问题称为并发问题。

2.3 实现callable接口

实现callable接口实现多线程需要重写call方法,而不是run方法。

@Override
    public Boolean call() throws Exception {
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url,fileName);
        System.out.println("下载文件"+fileName);

        return true;
    }

在调用时与上面连个的不同是callable使用的是创建服务提交服务的方法。

 public static void main(String[] args) throws ExecutionException, InterruptedException {
        ThreadDemo02 t1 = new ThreadDemo02("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595477956679&di=6086c0909a5a4499ab5784c42ea20183&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201901%2F17%2F20190117230425_eofqv.thumb.700_0.jpg","t1.jpg");
        ThreadDemo02 t2 = new ThreadDemo02("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595477956679&di=6086c0909a5a4499ab5784c42ea20183&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201901%2F17%2F20190117230425_eofqv.thumb.700_0.jpg","t2.jpg");
        ThreadDemo02 t3 = new ThreadDemo02("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595477956679&di=6086c0909a5a4499ab5784c42ea20183&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201901%2F17%2F20190117230425_eofqv.thumb.700_0.jpg","t3.jpg");

//        创建执行服务
        ExecutorService service = Executors.newFixedThreadPool(3);

//        提交执行
        Future<Boolean> r1 = (Future<Boolean>) service.submit(t1);
        Future<Boolean> r2 = (Future<Boolean>) service.submit(t2);
        Future<Boolean> r3 = (Future<Boolean>) service.submit(t3);



//        获取返回集
        Boolean rs1 = r1.get();
        Boolean rs2 = r2.get();
        Boolean rs3 = r3.get();


    //        关闭服务
        service.shutdown();

    }

相较于前面两个的好处是可以自定义返回值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值