首页 > 编程语言 > 详细

Java多线程

时间:2021-09-09 04:10:34      阅读:37      评论:0      收藏:0      [点我收藏+]

线程简介

任务

多任务:

技术分享图片

进程

线程

多线程

技术分享图片

程序、进程、线程

技术分享图片

进程Process和线程Thread

  • 说起进程,就不得不说下程序。程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
  • 而进程是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位。
  • 通常在一个进程中可以包含多个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是CPU调度和执行的单位。

注意:很多多线程是模拟出来的,真正的多线程是指有多个CPU,即多核处理器,如服务器。如果是模拟出来的多线程,即在一个CPU的情况下,在同一个时间点,CPU只能执行一个代码,因为切换的很快,所以就有了同时执行的错觉。

本章核心概念

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

线程实现(重点)

继承Thread类

创建线程

三种创建方式:

技术分享图片

技术分享图片

普通方法调用和多线程:

技术分享图片

package com.thread.demo01;

/*
    创建线程的方式一:
    1.继承Thread类
    2.重写run()方法
    3.调用start开启线程
注意:线程开启不一定立即执行,由CPU调度执行,无法人为干预
 */
public class ThreadTest01 extends Thread {
    @Override
    public void run() {
        //run()方法线程体
        for (int i = 0; i < 100; i++) {
            System.out.println("我在看代码----" + i);
        }
    }

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

        //创建线程对象
        ThreadTest01 threadTest01 = new ThreadTest01();
        //调用start()方法开启线程,两个线程同时执行
        threadTest01.start();
//        threadTest01.run(); //先执行run()方法再执行后面,按顺序执行,只有一个线程

        for (int i = 0; i < 500; i++) {
            System.out.println("我在学习多线程----" + i);
        }
    }
}

使用多线程下载图片

技术分享图片

谷歌下载Commons IO包,把commons-io.jar包复制到项目中,需要把包Add as Library添加到库。

package com.thread.demo01;

import org.apache.commons.io.FileUtils;

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

//使用多线程同时下载图片
public class ThreadTest02 extends Thread {
    private String url;
    private String name;

    public ThreadTest02(String url, String name) {
        this.url = url; //网络图片地址
        this.name = name; //保存的文件名
    }

    //下载图片线程的执行体
    @Override
    public void run() {
        WebDownload webDownload = new WebDownload();
        webDownload.download(url, name);
        System.out.println("下载的文件名为:" + name);
    }

    public static void main(String[] args) {
        //创建线程对象
        ThreadTest02 thread01 = new ThreadTest02("https://pic3.zhimg.com/50/v2-5de178c64e85f84cd8c38590ab0e205f_720w.jpg?source=1940ef5c", "1.jpg");
        ThreadTest02 thread02 = new ThreadTest02("https://pic2.zhimg.com/50/v2-6738a21df443d5c52f52df93464d2034_720w.jpg?source=1940ef5c", "2.jpg");
        ThreadTest02 thread03 = new ThreadTest02("https://pica.zhimg.com/50/v2-898c55d1a93136b6c716ddfba4c8b7c9_720w.jpg?source=1940ef5c", "3.jpg");

        //开启线程
        //理想执行顺序是:先下载t1,然后t2,最后t3
        //实际执行顺序是:t1,t3,t2,每次执行顺序可能都不一样
        thread01.start();
        thread02.start();
        thread03.start();
    }
}

//下载器
class WebDownload {
    //下载方法
    public void download(String url, String name) {
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,download方法出现问题");
        }
    }
}

实现Runnable接口

创建线程推荐使用方式二,实现Runnable接口

package com.thread.demo01;

/*
    创建线程方法二:实现Runnable接口,重写run()方法,执行线程需要丢入runnable接口
 */
public class ThreadTest03 implements Runnable{
    @Override
    public void run() {
        //run方法线程体
        for (int i = 0; i < 100; i++) {
            System.out.println("我在看代码----" + i);
        }
    }

    public static void main(String[] args) {
        //创建Runnable接口的实现类对象
        ThreadTest03 thread03 = new ThreadTest03();

        //创建线程对象,通过线程对象开启线程,代理
//        Thread thread = new Thread(thread03);
//        thread.start();

        new Thread(thread03).start();

        for (int i = 0; i < 500; i++) {
            System.out.println("我在学习多线程----" + i);
        }
    }
}

小结:

技术分享图片

多个线程同时操作同一个对象

问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱!

package com.thread.demo01;

/*
    多个线程同时操作同一个对象
    场景:买火车票
    发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱!
 */
public class ThreadTest05 implements Runnable{
    //票数
    private int ticketNums = 10;

    @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) {
        ThreadTest05 ticket = new ThreadTest05();

        new Thread(ticket, "小明").start();
        new Thread(ticket, "小红").start();
        new Thread(ticket, "黄牛").start();
    }
}
龟兔赛跑

技术分享图片

package com.thread.demo01;

/*
    模拟龟兔赛跑
 */
public class Race implements Runnable{
    //胜利者
    private static String winner;

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            //模拟兔子休息
            if (Thread.currentThread().getName().equals("兔子") && i % 10 == 0) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //判断比赛是否结束
            boolean flag = gameOver(i);
            //如果比赛结束了,就停止程序
            if (flag) {
                break;
            }

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

    //判断是否完成比赛
    private boolean gameOver(int steps) {
        //判断是否有胜利者
        if (winner != null) { //已经有胜利者了
            return true;
        } else {
            if (steps == 100) {
                winner = Thread.currentThread().getName();
                System.out.println("winner is " + winner);
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        Race race = new Race();

        new Thread(race, "兔子").start();
        new Thread(race, "乌龟").start();
    }
}

实现Callable接口(了解)

技术分享图片

package com.thread.demo02;

import org.apache.commons.io.FileUtils;

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

/*
    线程创建方式三:实现Callable接口

    使用Callable的好处
    1.可以定义返回值类型
    2.可以抛出异常
 */
public class CallableTest implements Callable<Boolean> {
    private String url;
    private String name;

    public CallableTest(String url, String name) {
        this.url = url; //网络图片地址
        this.name = name; //保存的文件名
    }

    //下载图片线程的执行体
    @Override
    public Boolean call() {
        WebDownload webDownload = new WebDownload();
        webDownload.download(url, name);
        System.out.println("下载的文件名为:" + name);
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建线程对象
        CallableTest thread01 = new CallableTest("https://pic3.zhimg.com/50/v2-5de178c64e85f84cd8c38590ab0e205f_720w.jpg?source=1940ef5c", "1.jpg");
        CallableTest thread02 = new CallableTest("https://pic2.zhimg.com/50/v2-6738a21df443d5c52f52df93464d2034_720w.jpg?source=1940ef5c", "2.jpg");
        CallableTest thread03 = new CallableTest("https://pica.zhimg.com/50/v2-898c55d1a93136b6c716ddfba4c8b7c9_720w.jpg?source=1940ef5c", "3.jpg");

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

        //提交执行
        Future<Boolean> r1 = ser.submit(thread01);
        Future<Boolean> r2 = ser.submit(thread02);
        Future<Boolean> r3 = ser.submit(thread03);

        //获取结果
        Boolean rs1 = r1.get();
        Boolean rs2 = r2.get();
        Boolean rs3 = r3.get();

        //关闭服务
        ser.shutdown();
    }
}

//下载器
class WebDownload {
    //下载方法
    public void download(String url, String name) {
        try {
            FileUtils.copyURLToFile(new URL(url), new File(name));
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("IO异常,download方法出现问题");
        }
    }
}

静态代理模式

事例:

技术分享图片

package com.thread.demo03;

/*
    静态代理模式总结:
    真实对象和代理对象都要实现同一个接口
    代理对象要代理真实角色

    好处:
    代理对象可以做很多真实对象做不了的事情
    真实对象专注做自己的事情
 */
public class StaticProxy {
    public static void main(String[] args) {
//        You you = new You(); // 你要结婚
//        WeddingCompany weddingCompany = new WeddingCompany(you);

        new Thread( ()-> System.out.println("我爱你") ).start();

        new WeddingCompany(new You()).HappyMarry();

//        WeddingCompany weddingCompany = new WeddingCompany(new You());
//        weddingCompany.HappyMarry();
    }
}

interface Marry{
    /*
    人间四大喜事
        久旱逢甘露
        他乡遇故知
        洞房花烛夜
        金榜题名时
     */
    void HappyMarry();
}

//真实角色,你去结婚
class You implements Marry {

    @Override
    public void HappyMarry() {
        System.out.println("要结婚了,很开心!");
    }
}

//代理角色,帮助你结婚
class WeddingCompany implements Marry {

    //代理谁--》真实目标角色
    private Marry target;

    public WeddingCompany(Marry target) {
        this.target = target;
    }

    @Override
    public void HappyMarry() {
        before();
        this.target.HappyMarry(); //这就是真实对象
        after();
    }

    private void after() {
        System.out.println("结婚之前,布置现场");
    }

    private void before() {
        System.out.println("结婚之后,收尾款");
    }
}

Lambda表达式

技术分享图片

技术分享图片

技术分享图片

推导Lambda表达式

package com.thread.demo04;

/*
    推导Lambda表达式
 */
public class LambdaTest01 {

    //3.静态内部类
    static class Like2 implements ILike {
        @Override
        public void lambda() {
            System.out.println("i like lambda2");
        }
    }

    public static void main(String[] args) {
        ILike like = new Like(); //接口指向实现类
        like.lambda();

        like = new Like2();
        like.lambda();

        //4.局部内部类
        class Like3 implements ILike {
            @Override
            public void lambda() {
                System.out.println("i like lambda3");
            }
        }
        like = new Like3();
        like.lambda();

        //5.匿名内部类,没有类的名称,必须借助接口或者父类
        like = new ILike() {
            @Override
            public void lambda() {
                System.out.println("i like lambda4");
            }
        };
        like.lambda();

        //6.用Lambda简化
        like = ()-> {
            System.out.println("i like lambda5");
        };
        like.lambda();

    }
}

//1.定义一个函数式接口
interface ILike {
    void lambda();
}

//2.实现类
class Like implements ILike {
    @Override
    public void lambda() {
        System.out.println("i like lambda");
    }
}

Lambda表达式简化

package com.thread.demo04;public class LambdaTest02 {    //3.静态内部类    static class Love implements ILove {        @Override        public void love(int a) {            System.out.println("i love you" + a);        }    }    public static void main(String[] args) {        //4.局部内部类        class Love implements ILove {            @Override            public void love(int a) {                System.out.println("i love you" + a);            }        }        ILove love = new Love();        love.love(2);        //5.匿名内部类        ILove love2 = new ILove() {            @Override            public void love(int a) {                System.out.println("i love you" + a);            }        };        love2.love(3);        //6.Lambda表达式,简化        ILove love3 = (int a)-> {            System.out.println("i love you" + a);        };        love3.love(4);        //简化1:去掉参数类型        ILove love4 = (a)-> {            System.out.println("i love you" + a);        };        love4.love(5);        //简化2:去掉括号()        ILove love5 = a-> {            System.out.println("i love you" + a);        };        love5.love(6);        //简化3:去掉花括号{}        ILove love6 = a-> System.out.println("i love you" + a);        love6.love(7);        /*            总结:            Lambda表达式只能有一行代码的情况下才能简化成一行,如果有多行,那么就用代码块括起来。            使用Lambda表达式的前提,接口必须是函数式接口            多个参数也可以去掉参数类型,要去掉就都去掉,必须加上括号()!         */    }}//1.定义一个函数式接口interface ILove {    void love(int a);}//2.实现类class Love implements ILove {    @Override    public void love(int a) {        System.out.println("i love you" + a);    }}

线程状态

线程五大状态:

技术分享图片

技术分享图片

线程方法

技术分享图片

停止线程

技术分享图片

package com.thread.demo05;/*    停止线程    1.建议线程正常停止--->利用次数,不建议死循环。    2.建议使用标志位--->设置一个标志位    3.不要使用stop或者destroy等过时方法,以及JDK不建议使用的方法 */public class ThreadStopTest01 implements Runnable {    //1.设置一个标志位    private boolean flag = true;    @Override    public void run() {        int i = 0;        while (flag) {            System.out.println("run...Thread" + i++);        }    }    //2.设置一个公开的方法停止线程,改变标志位    public void stop() {        this.flag = false;    }    public static void main(String[] args) {        ThreadStopTest01 threadStop = new ThreadStopTest01();        new Thread(threadStop).start();        for (int i = 0; i < 1000; i++) {            System.out.println("main" + i);            if (i == 900) {                //调用stop()方法改变标志位,让线程停止                threadStop.stop();                System.out.println("线程已停止");            }        }    }}

线程休眠

技术分享图片

模拟网络延时:

package com.thread.demo05;/*    线程休眠    事例:模拟网络延时    模拟网络延时的作用:放大问题的发生性 */public class ThreadSleepTest01 implements Runnable {    //票数    private int ticketNums = 10;    @Override    public void run() {        while (true) {            if (ticketNums <= 0) {                break;            }            try {                //线程睡眠,模拟延时                Thread.sleep(100);            } catch (InterruptedException e) {                e.printStackTrace();            }            System.out.println(Thread.currentThread().getName() + "-->拿到了第" + ticketNums-- + "张票");        }    }    public static void main(String[] args) {        ThreadSleepTest01 ticket = new ThreadSleepTest01();        new Thread(ticket, "小明").start();        new Thread(ticket, "小红").start();        new Thread(ticket, "黄牛").start();    }}

模拟倒计时:

package com.thread.demo05;import java.text.SimpleDateFormat;import java.util.Date;/*    线程休眠    事例:模拟倒计时 */public class ThreadSleepTest02 {    public static void main(String[] args) {        try {            ThreadSleepTest02.tenDown();        } catch (InterruptedException e) {            e.printStackTrace();        }        //打印当前系统时间        Date start = new Date(System.currentTimeMillis()); //获取系统当前时间        while (true) {            try {                Thread.sleep(1000);                System.out.println(new SimpleDateFormat("HH:mm:ss").format(start));                start = new Date(System.currentTimeMillis()); //更新当前时间            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    //模拟倒计时    public static void tenDown() throws InterruptedException {        int num = 10;        while (true) {            Thread.sleep(1000);            System.out.println(num--);            if (num <= 0) {                break;            }        }    }}

线程礼让

技术分享图片

package com.thread.demo05;/*    线程礼让    礼让不一定成功,看CPU心情 */public class ThreadYield {    public static void main(String[] args) {        MyYield myYield = new MyYield();        new Thread(myYield, "a").start();        new Thread(myYield, "b").start();    }}class MyYield implements Runnable {    @Override    public void run() {        System.out.println(Thread.currentThread().getName() + "线程开始执行");        Thread.yield(); //线程礼让        System.out.println(Thread.currentThread().getName() + "线程结束执行");    }}

线程插队

技术分享图片

package com.thread.demo05;/*    线程插队join()    可以想象成插队 */public class ThreadJoinTest01 implements Runnable {    @Override    public void run() {        for (int i = 0; i < 100; i++) {            System.out.println("线程vip来了" + i);        }    }    public static void main(String[] args) throws InterruptedException {        //启动线程        ThreadJoinTest01 threadJoin = new ThreadJoinTest01();        Thread thread = new Thread(threadJoin);        thread.start();        //主线程        for (int i = 0; i < 1000; i++) {            if (i == 200) {                thread.join(); //插队            }            System.out.println("main" + i);        }    }}

观测线程状态

技术分享图片

技术分享图片

package com.thread.demo05;/*    观察测试线程的状态 */public class ThreadStateTest01 {    public static void main(String[] args) throws InterruptedException {        Thread thread = new Thread(()-> {            for (int i = 0; i < 5; i++) {                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            System.out.println(".......");        });        //观察线程状态        Thread.State state = thread.getState();        System.out.println(state); //NEW        //观察启动后        thread.start(); //启动线程        state = thread.getState();        System.out.println(state); //RUNNABLE        while (state != Thread.State.TERMINATED) { //只要线程不终止,就一直输出状态            Thread.sleep(100);            state = thread.getState(); //更新线程状态            System.out.println(state); //输出线程状态        }    }}

线程优先级

技术分享图片

守护线程

技术分享图片

package com.thread.demo05;/*    守护线程    事例:上帝守护着你 */public class ThreadDaemonTest01 {    public static void main(String[] args) {        God god = new God();        You you = new You();        Thread thread = new Thread(god);        thread.setDaemon(true); //默认是false表示用户线程,正常的线程都是用户线程        thread.start(); //上帝守护线程启动        new Thread(you).start(); //你,用户线程启动    }}//上帝class God implements Runnable {    @Override    public void run() {        while (true) {            System.out.println("上帝保佑着你");        }    }}//你class You implements Runnable {    @Override    public void run() {        for (int i = 0; i < 36500; i++) {            System.out.println("你一生都开心的活着!");        }    }}

线程同步(重点)

多个线程操作同一个资源

线程同步机制

并发

技术分享图片

线程同步

技术分享图片

技术分享图片

队列和锁

技术分享图片

三大不安全事例

同步方法

技术分享图片

同步方法的弊端

技术分享图片

同步块

技术分享图片

同步方法:

package com.thread.demo06;/*    不安全的买票 */public class ThreadUnsafeBuyTicket {    public static void main(String[] args) {        BuyTicket station = new BuyTicket();        new Thread(station, "机智如我").start();        new Thread(station, "难搞的你们").start();        new Thread(station, "可恶的黄牛").start();    }}class BuyTicket implements Runnable {    //票    private int ticketNums = 10;    boolean flag = true; //外部停止方式    @Override    public void run() {        //买票        while (flag) {            buy();        }    }    //synchronized 同步方法,锁的是this    private synchronized void buy() {        //判断是否有票        if (ticketNums <= 0) {            flag = false;            return;        }        //模拟延时        try {            Thread.sleep(100);        } catch (InterruptedException e) {            e.printStackTrace();        }        //买票        System.out.println(Thread.currentThread().getName() + "拿到第" + ticketNums-- + "张票");    }}

同步块:

package com.thread.demo06;/*    不安全的取钱    事例:两个人去银行取钱,需要账户 */public class ThreadUnsafeBank {    public static void main(String[] args) {        //账户        Account account = new Account(1000, "结婚基金");        Drawing you = new Drawing(account, 50, "你");        Drawing girlFriend = new Drawing(account, 100, "girlFriend");        you.start();        girlFriend.start();    }}//账户class Account {    int money; //余额    String name; //卡名    public Account(int money, String name) {        this.money = money;        this.name = name;    }}//银行:模拟取款class Drawing extends Thread {    Account account;    //取了多少钱    int drawingMoney;    //现在手里有多少钱    int nowMoney;    public Drawing(Account account, int drawingMoney, String name) {        super(name);        this.account = account;        this.drawingMoney = drawingMoney;    }    //取钱    //synchronized 默认锁的是this    @Override    public void run() {        //同步块        //锁的对象就是变化的量        synchronized (account) {            //判断有没有钱            if (account.money - drawingMoney < 0) {                System.out.println(Thread.currentThread().getName() + "钱不够,取不了");                return;            }            //模拟延时,可以放大问题的发生性            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }            //卡内余额 = 余额 - 你取的钱            account.money = account.money - drawingMoney;            //你手里的钱            nowMoney = nowMoney + drawingMoney;            System.out.println(account.name + "余额为:" + account.money);            System.out.println(this.getName() + "手里的钱:" + nowMoney);//        System.out.println(Thread.currentThread().getName() + "手里的钱:" + nowMoney);        }    }}

死锁

技术分享图片

死锁避免方法

技术分享图片

package com.thread.demo07;/*    死锁    死锁:多个线程互相持有对方需要的资源,然后形成僵持 */public class DeadLock {    public static void main(String[] args) {        Makeup girl1 = new Makeup(0, "亚丝娜");        Makeup girl2 = new Makeup(1, "加藤惠");        girl1.start();        girl2.start();    }}//口红class Lipstick {}//镜子class Mirror {}//化妆class Makeup extends Thread {    //需要的资源只有一份,用static来保证    static Lipstick lipstick = new Lipstick();    static Mirror mirror = new Mirror();    int choice; //选择    String girlName; //使用化妆品的人    Makeup(int choice, String girlName) {        this.choice = choice;        this.girlName = girlName;    }    @Override    public void run() {        //化妆        makeup();    }    //化妆,互相持有对方的锁,就是需要拿到对方的资源    private void makeup() {        if (choice == 0) {            synchronized (lipstick) { //获得口红的锁                System.out.println(this.girlName + "获得口红的锁");                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }////                synchronized (mirror) { //一秒钟后想获得镜子的锁//                    System.out.println(this.girlName + "获得镜子的锁");//                }            }            //把同步块拿出来,就可以解决死锁问题            synchronized (mirror) { //一秒钟后想获得镜子的锁                System.out.println(this.girlName + "获得镜子的锁");            }        } else {            synchronized (mirror) { //获得镜子的锁                System.out.println(this.girlName + "获得镜子的锁");                try {                    Thread.sleep(2000);                } catch (InterruptedException e) {                    e.printStackTrace();                }////                synchronized (lipstick) { //一秒钟后想获得口红的锁//                    System.out.println(this.girlName + "获得口红的锁");//                }            }            synchronized (lipstick) { //一秒钟后想获得口红的锁                System.out.println(this.girlName + "获得口红的锁");            }        }    }}

Lock(锁)

技术分享图片

技术分享图片

技术分享图片

package com.thread.demo08;import java.util.concurrent.locks.ReentrantLock;/*    Lock锁 */public class LockTest {    public static void main(String[] args) {        LockTest2 lockTest2 = new LockTest2();        new Thread(lockTest2).start();        new Thread(lockTest2).start();        new Thread(lockTest2).start();    }}class LockTest2 implements Runnable {    int ticketNums = 10;    //定义Lock锁    private final ReentrantLock lock = new ReentrantLock();    @Override    public void run() {        while (true) {            try {                //加锁                lock.lock();                if (ticketNums > 0) {                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    System.out.println(ticketNums--);                } else {                    break;                }            }  finally {                //解锁                lock.unlock();            }        }    }}

线程通信

生产者消费者模式

生产者消费者问题

技术分享图片

技术分享图片

技术分享图片

技术分享图片

技术分享图片

管程法

技术分享图片

package com.thread.demo08;/*    生产者消费者模型-->利用缓冲区解决:管程法    要素:生产者,消费者,产品,缓冲区 */public class PCTest {    public static void main(String[] args) {        SynContainer container = new SynContainer();        new Producer(container).start();        new Consumer(container).start();    }}//生产者class Producer extends Thread {    SynContainer container;    public Producer(SynContainer container) {        this.container = container;    }    //生产    @Override    public void run() {        for (int i = 0; i < 100; i++) {            System.out.println("生产了" + i + "只鸡");            container.push(new Chicken(i));        }    }}//消费者class Consumer extends Thread {    SynContainer container;    public Consumer(SynContainer container) {        this.container = container;    }    //消费    @Override    public void run() {        for (int i = 0; i < 100; i++) {            System.out.println("消费了-->" + container.pop().id + "只鸡");        }    }}//产品class Chicken {    int id; //产品编号    public Chicken(int id) {        this.id = id;    }}//缓冲区class SynContainer {    //需要一个容器的大小    Chicken[] chickens = new Chicken[10];    //容器计数器    int count = 0;    //生产者放入产品    public synchronized void push(Chicken chicken) {        //如果容器满了,就需要等待消费者消费        if (count == chickens.length) {            //通知消费者消费,生产者等待            try {                this.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        //如果没有满,我们就要丢入产品        chickens[count] = chicken;        count++;        //可以通知消费者消费了        this.notifyAll();    }    //消费者消费产品    public synchronized Chicken pop() {        //判断是否能消费        if (count == 0) {            //等待生产者生产,消费者等待            try {                this.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        //如果可以消费        count--;        Chicken chicken = chickens[count];        //吃完了,通知生产者生产        this.notifyAll();        return chicken;    }}

信号灯法

技术分享图片

package com.thread.demo08;/*    生产者消费者模型2-->利用标志位解决:信号灯法 */public class PCTest02 {    public static void main(String[] args) {        Program program = new Program();        new actor(program).start();        new audience(program).start();    }}//生产者-->演员class actor extends Thread {    Program program;    public actor(Program program) {        this.program = program;    }    @Override    public void run() {        for (int i = 0; i < 20; i++) {            if (i % 2 == 0) {                this.program.play("快乐大本营播放中");            } else {                this.program.play("抖音,记录美好生活");            }        }    }}//消费者-->观众class audience extends Thread {    Program program;    public audience(Program program) {        this.program = program;    }    @Override    public void run() {        for (int i = 0; i < 20; i++) {            program.watch();        }    }}//产品-->节目class Program{    //演员表演,观众等待 true    //观众观看,演员等待 false    String voice; //表演的节目    boolean flag = true;    //表演    public synchronized void play(String voice) {        if (!flag) {            try {                this.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        System.out.println("演员表演了:" + voice);        //通知观众观看        this.notifyAll(); //通知唤醒        this.voice = voice;        this.flag = !this.flag;    }    //观看    public synchronized void watch() {        if (flag) {            try {                this.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        System.out.println("观看了:" + voice);        //通知演员表演        this.notifyAll();        this.flag = !this.flag;    }}

线程池

技术分享图片

技术分享图片

package com.thread.demo08;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;/*    线程池 */public class ThreadPoolTest {    public static void main(String[] args) {        //1.创建服务,创建线程池        //newFixedThreadPool 参数为:线程池大小        ExecutorService service = Executors.newFixedThreadPool(10);        service.execute(new MyThread());        service.execute(new MyThread());        service.execute(new MyThread());        service.execute(new MyThread());        //2.关闭连接        service.shutdown();    }}class MyThread implements Runnable {    @Override    public void run() {        System.out.println(Thread.currentThread().getName());    }}

多线程总结

线程实现的三个方式,锁

package com.thread.demo09;import java.util.concurrent.Callable;import java.util.concurrent.ExecutionException;import java.util.concurrent.FutureTask;/*    总结    线程实现的三个方式 */public class AllInOne {    public static void main(String[] args) {        new MyThread1().start();        new Thread(new MyThread2()).start();        FutureTask<Integer> futureTask = new FutureTask<>(new MyThread3());        new Thread(futureTask).start();        try {            Integer integer = futureTask.get();            System.out.println(integer);        } catch (InterruptedException e) {            e.printStackTrace();        } catch (ExecutionException e) {            e.printStackTrace();        }    }}//1.继承Thread类class MyThread1 extends Thread {    @Override    public void run() {        System.out.println("MyThread1");    }}//2.实现Runnable接口class MyThread2 implements Runnable {    @Override    public void run() {        System.out.println("MyThread2");    }}//3.实现Callable接口class MyThread3 implements Callable<Integer> {    @Override    public Integer call() throws Exception {        System.out.println("MyThread3");        return 100;    }}

Java多线程

原文:https://www.cnblogs.com/hongchengg/p/15239547.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!