java多线程

多线程

创建线程的方式一,继承Thread类

package threadText;

//创建线程的方式一,继承thread类,重写run方法,使用Start开启
//注意,线程开启不一定立即执行,由cpu调度
public class ThreadText01 extends Thread{
    //重写run方法
    @Override
    public void run() {
       //run方法体
        for (int i = 0; i < 10; i++) {
            System.out.println("我是Thread"+i);
        }
    }

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

        //创建一个线程对象
        ThreadText01 threadText01 = new ThreadText01();
        //开启线程
        threadText01.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("我是main函数"+i);
        }
    }
}

同时下载3张图片

package threadText;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

//练习Thread,同步下载图片
public class ThreadText02 extends Thread{

    private String url;//网络图片地址
    private String name;//文件名

    public ThreadText02(String url, String name) {
        this.name=name;
        this.url=url;
    }

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

    public static void main(String[] args) {
        ThreadText02 t1 = new ThreadText02("http://00.minipic.eastday.com/20170106/20170106165023_a14bfa564f46922451f7f43cd86ffd67_9.jpeg","9.jpeg");
        ThreadText02 t2 = new ThreadText02("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581247708&di=7b6c1bd628e2a29ac0ac724c9c8c9a8f&imgtype=jpg&er=1&src=http%3A%2F%2Fimg.kutoo8.com%2Fupload%2Fimage%2F72604229%2F14%2520%281%29_960x540.jpg","10.jpg");
        ThreadText02 t3 = new ThreadText02("http://pic1.win4000.com/pic/3/23/3c411423997.jpg","11.jpg");

        t1.start();
        t2.start();
        t3.start();
    }
}
//下载器
class webDownloader{
    //下载方法
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("下载异常,webDownloader");
        }

    }
}
//下载顺序
//下载文件名为11.jpg
//下载文件名为9.jpeg
//下载文件名为10.jpg
//不一定是开启顺序

创建线程方式2,实现Runnable接口

package threadText;

//创建线程方式2,实现runnable接口,重写run方法,执行线程需要丢入runnable接口实现类,调用start方法
public class ThreadText03 implements Runnable{
    //重写run方法
    @Override
    public void run() {
        //run方法体
        for (int i = 0; i < 10; i++) {
            System.out.println("我是Thread"+i);
        }
    }

    //main线程,主线程
    public static void main(String[] args) {
        //创建一个runnable接口的实现类对象
        ThreadText03 threadText03 = new ThreadText03();
        /*
        //创建线程对象,通过线程对象来开启我们的线程
        Thread thread = new Thread(threadText03);
        //开启
        thread.start();
        */
        //简写
        new Thread(threadText03).start();

        for (int i = 0; i < 20; i++) {
            System.out.println("我是main函数"+i);
        }
    }
}
  • 继承Thread类

    • 子类继承Thread类具备多线程能力
    • 启动线程:子类对象. start()
    • 不建议使用:避免0OP单继承局限性
  • 实现Runnable接口

    • 实现接口Runnable具有多线程能力
    • 启动线程:传入目标对象+Thread对象.start()
      推荐使用:避免单继承局限性,灵活方便,方便同一个对象被多个线程使用

龟兔赛跑案例

package threadText;
/*
    龟兔赛跑案例
    1.设置赛道距离,逐渐接近
    2.判断比赛是否结束
    3.打印出胜利者
    4.龟兔赛跑开始,模拟兔子睡觉
    5.乌龟胜利
*/
public class ThreadText04 implements Runnable{

    private static String winner;//静态保证只有一个

    @Override
    public void run() {
        //赛道建立
        for (int i = 0; i <= 100; i++) {

            //判断是否跑完,结束程序
            boolean gameover = gameover(i);
            if(gameover){
                break;
            }

            //兔子睡觉
            if(Thread.currentThread().getName().equals("兔子")&&i>=3){//currentThread()返回正在执行线程的对象
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            System.out.println(Thread.currentThread().getName()+"跑了第"+i+"步");
        }
    }



    //判断是否跑完
    public boolean gameover(int i){
        if(winner!=null){
            return true;
        }else if (i==100){
            winner=Thread.currentThread().getName();
            System.out.println(winner+"跑完了比赛");
            return true;
        }else {
            return false;
        }
    }

    public static void main(String[] args) {

        ThreadText04 threadText04 = new ThreadText04();
        new Thread(threadText04,"兔子").start();
        new Thread(threadText04,"乌龟").start();
    }
}

实现callable接口

  1. 实现callable接口,需要返回值类型
  2. 重写call方法,需要抛出异常
  3. 创建目标对象
  4. 创建执行任务,ExecutorService ser= Executors.newFixedThreadPool(1);
  5. 提交执行,Future resutl=ser.submit(t1);
  6. 获取结果,Boolean r1 = resutl.get();
  7. 关闭服务,ser.shutdownNow();
  • 好处
    • 可以实现返回值
    • 可以抛出异常
package threadText;

import org.apache.commons.io.FileUtils;

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

/*
    实现callable接口
*/
public class ThreadText05 implements Callable<Boolean> {


    private String url;//网络图片地址
    private String name;//文件名

    public ThreadText05(String url, String name) {
        this.name=name;
        this.url=url;
    }

    @Override
    public Boolean call() {
        webDownloaderr webDownloader = new webDownloaderr();
        webDownloader.downloader(url,name);
        System.out.println("下载文件名为"+name);

        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ThreadText05 t1 = new ThreadText05("http://00.minipic.eastday.com/20170106/20170106165023_a14bfa564f46922451f7f43cd86ffd67_9.jpeg","9.jpeg");
        ThreadText05 t2 = new ThreadText05("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581247708&di=7b6c1bd628e2a29ac0ac724c9c8c9a8f&imgtype=jpg&er=1&src=http%3A%2F%2Fimg.kutoo8.com%2Fupload%2Fimage%2F72604229%2F14%2520%281%29_960x540.jpg","10.jpg");
        ThreadText05 t3 = new ThreadText05("http://pic1.win4000.com/pic/3/23/3c411423997.jpg","11.jpg");

        //创建执行任务
        ExecutorService ser= Executors.newFixedThreadPool(1);
        //提交执行
        Future<Boolean> r1=ser.submit(t1);
        Future<Boolean> r2=ser.submit(t2);
        Future<Boolean> r3=ser.submit(t3);
        //获取结果
        Boolean rs1 = r1.get();
        Boolean rs2 = r2.get();
        Boolean rs3 = r2.get();
        //关闭服务
        ser.shutdownNow();

        System.out.println(rs1);
        System.out.println(rs2);
        System.out.println(rs3);
    }
}
//下载器
class webDownloaderr{
    //下载方法
    public void downloader(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("下载异常,webDownloader");
        }

    }
}

在这里插入图片描述

在这里插入图片描述

卖票,解决冲突

  • 同步代码块
package threadText02;

/*
    卖票实现,出现了安全问题

    解决方法一,使用同步代码块
    格式
        synchronize(锁对象){
            可能出现安全问题的代码(共享的代码)
        }
    注意
        1.通过代码块中的锁对象,可以是任意对象
        2.必须保证多个对象使用的锁对象是同一个
        3.锁对象的原理,把同步代码锁住,只让一个线程在同步代码中执行
*/
public class Demo01Thread {
    public static void main(String[] args) {

        //创建Runnable接口,实现类对象
        maipiao maipiao = new maipiao();
        //创建Thread对象,构造方法中传递Runnable接口,实现类对象
        Thread t1 = new Thread(maipiao);
        Thread t2 = new Thread(maipiao);
        Thread t3 = new Thread(maipiao);
        //开启线程
        t1.start();
        t2.start();
        t3.start();
    }
}
/*
package threadText02;
/*
    买票

public class maipiao implements Runnable{

    //实现代码

    Object obj=new Object();
    private int ticket=100;
    @Override
    public void run() {
        while(true){
            //同步代码块
            synchronized (obj){

                if(ticket>0){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"卖出了第"+ticket+"票");
                    ticket--;
                }
            }
        }
    }
}

*/
  • 同步方法
package threadText02;

/*
    卖票实现,出现了安全问题

    解决方法一,使用同步代码块
    格式
        synchronize(锁对象){
            可能出现安全问题的代码(共享的代码)
        }
    注意
        1.通过代码块中的锁对象,可以是任意对象
        2.必须保证多个对象使用的锁对象是同一个
        3.锁对象的原理,把同步代码锁住,只让一个线程在同步代码中执行
*/
public class Demo01Thread {
    public static void main(String[] args) {

        //创建Runnable接口,实现类对象
        maipiao maipiao = new maipiao();
        //创建Thread对象,构造方法中传递Runnable接口,实现类对象
        Thread t1 = new Thread(maipiao);
        Thread t2 = new Thread(maipiao);
        Thread t3 = new Thread(maipiao);
        //开启线程
        t1.start();
        t2.start();
        t3.start();
    }
}
/*
package threadText02;

    买票

public class maipiao implements Runnable{

    //实现代码

    Object obj=new Object();
    private int ticket=100;
    @Override
    public void run() {
        while(true){
            pp();
        }
    }
    //同步代码块
    public synchronized void pp(){

        if(ticket>0){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"卖出了第"+ticket+"票");
            ticket--;
        }
    }
}


*/
  • lock
package threadText02;

/*
    卖票实现,出现了安全问题

    解决方法一,使用同步代码块
    格式
        synchronize(锁对象){
            可能出现安全问题的代码(共享的代码)
        }
    注意
        1.通过代码块中的锁对象,可以是任意对象
        2.必须保证多个对象使用的锁对象是同一个
        3.锁对象的原理,把同步代码锁住,只让一个线程在同步代码中执行
*/
public class Demo01Thread {
    public static void main(String[] args) {

        //创建Runnable接口,实现类对象
        maipiao maipiao = new maipiao();
        //创建Thread对象,构造方法中传递Runnable接口,实现类对象
        Thread t1 = new Thread(maipiao);
        Thread t2 = new Thread(maipiao);
        Thread t3 = new Thread(maipiao);
        //开启线程
        t1.start();
        t2.start();
        t3.start();
    }
}
/*
package threadText02;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/*
    买票

public class maipiao implements Runnable{

    //实现代码

    Lock l =new ReentrantLock();
    private int ticket=100;
    @Override
    public void run() {
        while(true){
            //lock
            l.lock();
            if(ticket>0){
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"卖出了第"+ticket+"票");
                ticket--;
            }
            l.unlock();
        }
    }

}

*/

线程之间的通信

  • 生产者与消费者问题

在这里插入图片描述

package shengchanzhe;
/*
    测试类
        包含main方法,程序的入口
        创建包子对象
        创建包子铺线程,开启,生产包子
        创建吃货线程,开启,吃包子
*/
public class Demo {

    public static void main(String[] args) {
        //创建包子对象
        baoZi bz = new baoZi();
        //创建包子铺线程,开启,生产包子
        new BaoZiPu(bz).start();
        //创建吃货线程,开启,吃包子
        new ChiHuo(bz).start();
    }
}

package shengchanzhe;
/*
    消费者(吃货)类:是一个线程类,可以继承Thread
    设置线程任务(run):吃包子
    对包子的状态进行判断
    false:没有包子
        吃货调用woit方法进入等待状态
    true:有包子
        吃货吃包子
        吃货吃完包子
        修改包子的状态为false没有
        吃货唤醒包子铺线程 ,生产包子
*/
public class ChiHuo extends Thread{

    private baoZi bz;
    public ChiHuo(baoZi bz) {
        this.bz = bz;
    }

    @Override
    public void run() {
        // 吃货调用woit方法进入等待状态
        while(true) {
            synchronized (bz) {
                if (bz.flag == false) {
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //被唤醒的线程
                System.out.println("吃货正在吃" + bz.pi + bz.xian + "包子");
                //吃货吃包子
                // 吃货吃完包子
                bz.flag = false;
                //吃货唤醒包子铺线程 ,生产包子
                bz.notify();
                System.out.println("吃货吃完了" + bz.pi + bz.xian + "包子,开始生产");
                System.out.println("=================================================");
            }
        }
    }
}


package shengchanzhe;
/*
    生产者,包子铺,是一个线程类,可以继承Thread
    设置线程任务(run),生产包子
    对包子的状态进行判定
        turn,有包子,调用wait方法进入等待状态
        false,没有包子
            包子铺生产包子
            增加一些趣味性,生产两种包子
                有两种状态(i%2==0)
            包子铺生产好包子
            修改包子的状态为true
            唤醒吃货线程吃包子

    注意
        包子线程与包子铺线程之间的关系————》通信(互斥)
        必须使用同步技术,是这两个线程只有个在执行
        锁对象必须保证唯一,可以使用包子对象作为锁对象
        包子铺类与吃货类,需要把包子对象作为参数传递进来
            1.需要在成员位置创建包子变量
            2.使用带参构造方法,为这个包子赋值
*/
public class BaoZiPu extends Thread{

    private baoZi bz;
    int count=0;
    public BaoZiPu(baoZi bz) {
        this.bz = bz;
    }

    @Override
    public void run() {

        //让包子铺一直生产包子
        while(true){
            synchronized (bz) {
                //turn,有包子,调用wait方法进入等待状态
                if (bz.flag == true) {
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                //被唤醒之后执行的代码
                // false,没有包子
                //增加一些趣味性,生产两种包子
                if (count % 2 == 0) {
                    bz.pi = "薄皮";
                    bz.xian = "三鲜馅";
                }else{
                    bz.pi = "厚皮";
                    bz.xian = "韭菜馅";
                }
                count++;
                System.out.println("包子铺正在生产"+bz.pi+bz.xian+"包子");
                //需要3000毫秒
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //包子铺生产好包子
                // 修改包子的状态为true
                bz.flag=true;
                //唤醒吃货线程吃包子
                bz.notify();
                System.out.println("包子铺生产好了"+bz.pi+bz.xian+"包子,可以开始吃了");
            }
        }
    }
}

package shengchanzhe;
/*
    资源类,包子类
    设置包子的属性
        皮
        馅
        包子的状态,有、无
*/
public class baoZi {
    //皮
    String pi;
    //馅
    String xian;
    //包子的状态
    boolean flag=false;
}

线程状态

在这里插入图片描述

等待唤醒案例

package threadText;
/*
    等待唤醒案例,线程之间的通信
        创建一个顾客线程,告知老板需要的包子个数以及种类,调用wait方法,放弃cpu使用权,进入到WAITING状态(无线等待)
        创建一个老板线程,花费5秒制作包子,报字制作完成,使用notify方法,告知顾客吃包子
        可以加死循环,让其一直工作

    注意
        老板线程与顾客线程要使用同步代码块包裹
        同步使用锁,必须对象一致
        只用锁对象才能调用wait与notify方法

    Object类中的方法
        void wait() 导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法
        void notify() 唤醒正在等待对象监视器的单个线程,会唤醒wait之后的代码
*/
public class Demo02Thread {
    public static void main(String[] args) {
        //创建锁对象
        Object ob=new Object();
        //创建一个顾客线程
        new Thread(){
            @Override
            public void run() {
                //保证只有一个执行
               synchronized(ob){
                   System.out.println("告知老板需要的包子个数以及种类");
                   try {
                       ob.wait();
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   //唤醒之后执行,wait之后的代码
                   System.out.println("包子好了,开吃");
                   System.out.println("=======================================");
               }
            }
        }.start();

        //创建一个老板线程
        new Thread(){
            @Override
            public void run() {
                //保证只有一个执行
                synchronized(ob){
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("包子制作完成");
                    ob.notify();
                }
            }
        }.start();
    }
}

notify与notifyAll

package threadText;
/*
    进入到TimeWaiting(计时等待)两种方式
        1.使用使用sleep(long m),在睡醒后进入,Runnable或者Blocked状态
        2.使用wait(long m),wait中设置的毫秒值结束之后,还没用被notify唤醒就会自动醒来,线程进入Runnable或者Blocked状态
*/
public class Demo03Thread {
    public static void main(String[] args) {
        //创建锁对象
        Object ob=new Object();
        //创建一个顾客线程
        new Thread(){
            @Override
            public void run() {
                //保证只有一个执行
                synchronized(ob){
                    System.out.println("顾客一告知老板需要的包子个数以及种类");
                    try {
                        ob.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //唤醒之后执行,wait之后的代码
                    System.out.println("包子好了,顾客一开吃");
                    System.out.println("=======================================");
                }
            }
        }.start();

        //创建一个顾客线程
        new Thread(){
            @Override
            public void run() {
                //保证只有一个执行
                synchronized(ob){
                    System.out.println("顾客二告知老板需要的包子个数以及种类");
                    try {
                        ob.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //唤醒之后执行,wait之后的代码
                    System.out.println("包子好了,顾客二开吃");
                    System.out.println("=======================================");
                }
            }
        }.start();

        //创建一个老板线程
        new Thread(){
            @Override
            public void run() {
                //保证只有一个执行
                synchronized(ob){
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("包子制作完成");
                    //ob.notify();//随机唤醒一个
                    ob.notifyAll();//全部唤醒
                }
            }
        }.start();
    }
}

线程池

  • 线程池,就是荣来多个线程得容器,其中的线程可以反复使用,省去了频繁创建线程的对象操作,无需反复创建线程而消耗过多资源。

在这里插入图片描述

package threadText;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/*
    线程池,JDK1.5之后出现
    java.util.concurrent.Executors,线程池工厂类,用来生成线程池
    Executors中的静态方法
        static ExecutorService newFixedThreadPool(int nThreads) 创建一个线程池,该线程池重用固定数量的从共享无界队列中运行的线程
        参数
            int nThreads,创建线程池的线程数
        返回值
            ExecutorService接口,返回ExecutorService接口实现类对象,我们可以使用ExecutorService接口接受(面向接口编程)

    java.util.concurrent.ExecutorService
        用来从线程池中获取线程,调用start方法执行线程
        submit(Runnable task) 提交一个Runnable任务执行
        关闭销毁线程池的方法
        void shutdown()

    线程池的使用步骤
        1.使用线程池的工厂类Executors类中的方法newFixedThreadPool,创建固定数量的线程池
        2.创建一个类,实现Runnable接口,重写run方法,设置线程任务
        3.使用ExecutorService中的方法submit,传递线程任务,开启线程
        4.使用shutdown关闭线程(不建议使用)
*/
public class Demo04Thread {
    public static void main(String[] args) {
        //1.使用线程池的工厂类Executors类中的方法newFixedThreadPool,创建固定数量的线程池
        ExecutorService es =Executors.newFixedThreadPool(2);
        //3.使用ExecutorService中的方法submit,传递线程任务,开启线程
        es.submit(new Demo04ThreadIpl());
        //线程池会一直开启,使用完线程,会自动把线程归还给线程池,线程可以继续使用
        es.submit(new Demo04ThreadIpl());
        es.submit(new Demo04ThreadIpl());

        //4.使用shutdown关闭线程(不建议使用)
        es.shutdown();
    }
}

/*
package threadText;
//2.创建一个类,实现Runnable接口,重写run方法,设置线程任务
public class Demo04ThreadIpl implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"正在执行");
    }
}
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值