2021-07-26 学习多线程

学习狂神java多线程,笔记记录

B站地址:
https://www.bilibili.com/video/BV1V4411p7EF?p=27&share_source=copy_web
gitee练习地址:
https://gitee.com/livieyifeng/damo-thread.git

概念

image.png

线程创建方式

image.png

image.png

image.png
package pyf.demo;

/**
 * @author pengyifeng
 * @version 1.0
 * @ClassName TestThreadDemo.java
 * @Description 线程创建方式1 继承Thread
 * @createTime 2021年07月26日 18:17:00
 */
public class TestThreadDemo01 extends Thread{

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("多线程运行:"+i);
        }
    }

    public static void main(String[] args) {

        //运行线程
        new TestThreadDemo01().start();
        //主线程
        for (int i = 0; i < 200; i++) {
            System.out.println("主线程运行:"+i);
        }
    }
}

package pyf.demo;

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName TestThreadDemo02.java
 * @Description 多线程方式2 实现Runnable
 * @createTime 2021年07月26日 18:21:00
 */
public class TestThreadDemo02 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"运行:"+i);
        }
    }

    public static void main(String[] args) {

        new Thread(new TestThreadDemo02(),"线程01").start();
        new Thread(new TestThreadDemo02(),"线程02").start();
        new Thread(new TestThreadDemo02(),"线程03").start();
        for (int i = 0; i < 100; i++) {
            System.out.println("主线程运行:"+i);
        }
    }
}

package pyf.demo;

import org.apache.commons.io.FileUtils;

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

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName TestThreadDemo03.java
 * @Description 多线程方式03 Callable
 * @createTime 2021年07月26日 18:25:00
 */
public class TestThreadDemo03 implements Callable {

    private String url;
    private String fileName;

    TestThreadDemo03(String url, String fileName){
        this.url=url;
        this.fileName=fileName;
    }
    @Override
    public Boolean call() throws Exception {
         new DownFile().down(url,fileName);
        return true;
    }

    class DownFile {

        public  void down(String url, String fileName) throws IOException {
            URL url1 = new URL(url);
            FileUtils.copyURLToFile(url1, new File("d:/img/" + fileName));
        }
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        TestThreadDemo03 t1=new TestThreadDemo03("https://blog.gitee.com/wp-content/uploads/2020/02/logo_blog_light.png", "下载1");
        TestThreadDemo03 t2=new TestThreadDemo03("https://blog.gitee.com/wp-content/uploads/2020/02/logo_blog_light.png", "下载2");
        TestThreadDemo03 t3=new TestThreadDemo03("https://blog.gitee.com/wp-content/uploads/2020/02/logo_blog_light.png", "下载3");
        //创建执行服务
        ExecutorService service= Executors.newFixedThreadPool(3);
        //提交执行
        Future f1 = service.submit(t1);
        Future f2 = service.submit(t2);
        Future f3 = service.submit(t3);

        //获取结果
        System.out.println(f1.get());
        System.out.println(f2.get());
        System.out.println(f3.get());

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


    }
}

多线程:静态代理

package pyf;

/**
 * 模仿线程静态代理
 * 场景:找商家代理购买手机
 *
 * you只关心你自己得事,比如买手机,但是各种原因买不到手机,所以需要代理商代买
 * you和shop都需要实现buy接口
 */
public class StaticProxy {

    public static void  main(String[] args) {
        You you = new You();
        new Shop(you).buyPhone();


    }

     static class You implements Buy {

        @Override
        public void buyPhone() {
            System.out.println("我非常想要这部手机");
        }
    }

    static class Shop implements Buy {

         private Buy target;

        public Shop(Buy target) {
            this.target = target;
        }

        void before() {
            System.out.println("收取定价,下单");
        }

        @Override
        public void buyPhone() {
            before();
            System.out.println("商家经过一系列操作购买到了手机");
            after();
        }

        void after() {
            System.out.println("收取尾款交货");
        }
    }

    /**
     * 购买行为
     */
    interface Buy {
        void buyPhone();
    }


}

image.png

image.png

image.png

image.png
package pyf.demo06;

/**
 * 线程休眠
 */
public class ThreadSleepDemo implements Runnable{
    private Integer num=10;

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if(timeOver(num)){
                try {
                    Thread.sleep(1000);

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("倒计时:"+num--);
            }
        }


    }
private boolean timeOver(int num){
        if(0>=num){
            System.out.println("倒计时结束");
            return false;
        }
        return true;
}
    public static void main(String[] args) {
       new Thread(new ThreadSleepDemo()).start();
    }
}

image.png
package pyf.demo07;

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName ThreadYieldDemo.java
 * @Description 线程礼让 yield 当前线程停止让下一个线程开始(礼让不确定,看cpu)
 * @createTime 2021年07月27日 09:32:00
 */
public class ThreadYieldDemo implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"开始");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"结束");
    }

    public static void main(String[] args) {
        new Thread(new ThreadYieldDemo(),"线程a").start();
        new Thread(new ThreadYieldDemo(),"线程b").start();
    }
}

礼让前


image.png

礼让后


image.png
image.png
package pyf;

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName ThreadJoinDemo.java
 * @Description join Demo
 * @createTime 2021年07月27日 09:44:00
 */
public class ThreadJoinDemo implements Runnable{
    @Override
    public void run() {
        System.out.println("vip插队");
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new ThreadJoinDemo());
        thread.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("main开始排队到第"+i);
            if(5==i){
                thread.join();
            }
        }
    }
}

image.png
image.png
package pyf.demo08;

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName ThreadStateDemo.java
 * @Description 线程状态
 * @createTime 2021年07月27日 09:57:00
 */
public class ThreadStateDemo{
    public static void main(String[] args) throws InterruptedException {

        Thread thread = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            System.out.println("线程运行");
        });

        //开始观察线程状态
        Thread.State state = thread.getState();
        System.out.println("启动前:"+state);

        //启动后
        thread.start();
        state = thread.getState();
        System.out.println("启动后:"+state);

        //只要线程不结束就一直运行
        while (!thread.getState().equals(Thread.State.TERMINATED)){
            Thread.sleep(100);
            //更新状态
            System.out.println(thread.getState());
        }
    }

}

image.png

image.png
package pyf.demo09;

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName ThreadPriorityDemo.java
 * @Description 线程优先等级设置 设置的优先级运行也是不准确的,看CPU
 * @createTime 2021年07月27日 10:18:00
 */
public class ThreadPriorityDemo {
    public static void main(String[] args) {
        //主线程优先等级
        System.out.println(Thread.currentThread().getName() + "==>" + Thread.currentThread().getPriority());

        MyThreadPriority myThreadPriority=new MyThreadPriority();
        Thread thread = new Thread(myThreadPriority,"线程a");
        thread.setPriority(Thread.MIN_PRIORITY);
        thread.start();
        Thread thread1 = new Thread(myThreadPriority,"线程b");
        thread1.setPriority(Thread.NORM_PRIORITY);
        thread1.start();
        Thread thread2 = new Thread(myThreadPriority,"线程c");
        thread2.setPriority(Thread.MAX_PRIORITY);
        thread2.start();

    }
static class MyThreadPriority implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"我的线程");
    }
}
}

image.png
image.png
package pyf.demo10;

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName ThreadDaemon.java
 * @Description 守护线程
 * 线程分为 用户线程 和 守护线程
 * 一般创建默认为用户线程
 * @createTime 2021年07月27日 10:42:00
 */
public class ThreadDaemon {

    static class You implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 36500; i++) {
                System.out.println("我是普通人已经生活了第" + i + "天");
            }
        }


    }

    static class God implements Runnable {
        @Override
        public void run() {
            while (true) {
                System.out.println("我是上帝与你同在");
            }
        }
    }

    public static void main(String[] args) {
        You you = new You();
        God god = new God();
        Thread thread = new Thread(you);
        Thread thread1 = new Thread(god);
        thread1.setDaemon(true);
        thread.start();
        thread1.start();
    }
}

线程同步问题

同时操作一个资源会出现并发问题

image.png

解决思路:使用队列和锁

image.png

实例1 多个人抢票造成的票数多买的情况

image.png

购票方法加上锁 synchronized

package pyf.demo11;

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName ThreadTicketDemo.java
 * @Description 抢票引发的并发问题 synchronized 
 * @createTime 2021年07月27日 10:54:00
 */
public class ThreadTicketDemo {



    static class BuyTicket implements Runnable {
        /**
         * 票
         */
        private Integer num = 10;
        private boolean  flag = true;

        @Override
        public void run() {
            while (flag){
                buy();
            }

        }

        private synchronized void buy() {
            //判断是否邮票
            if(num<0){
                flag=false;
                return;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "拿到第" + num-- + "票");
        }
    }

    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        new Thread(buyTicket,"黄牛").start();
        new Thread(buyTicket,"小明").start();
        new Thread(buyTicket,"小红").start();
    }
}

示例2 银行取钱 一共只有100 但是同时取钱造成余额为负

image.png

解决方法为修改的方法加上同步块 synchronized (target)

package pyf.demo11;

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName UnsafeBankDemo.java
 * @Description 模拟银行取钱 2个人同时取钱
 * @createTime 2021年07月27日 11:11:00
 */
public class UnsafeBankDemo {
    public static void main(String[] args) {
        Account account=new Account(100,"买房子的存款");
        Drawing you = new Drawing(account, 50, 0, "张三");
        Drawing girl = new Drawing(account, 100, 0, "张三的女票");
        you.start();
        girl.start();
    }
    /**
     * 账户
      */
    static class Account{
    //余额
    int money;
    //人名
    String name;

        public Account(int money, String name) {
            this.money = money;
            this.name = name;
        }
    }

    /**
     * 模拟银行钱
      */
    static class Drawing extends Thread{

    private Account account;
    private int drawingMoney;
    private int nowMoney;
    Drawing(Account account,int drawingMoney,int nowMoney,String name){
        super(name);
        this.account=account;
        this.drawingMoney=drawingMoney;
        this.nowMoney=nowMoney;
    }
    @Override
    public void run() {
        synchronized (account){
            //判断银行没有钱
            if(account.money-drawingMoney<0){
                System.out.println(Thread.currentThread().getName()+"取款余额不足:"+account.money);
                return;
            }
            //模拟取钱延时场景
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            account.money=account.money-drawingMoney;
            System.out.println(account.name + "余额为:" + account.money);
            nowMoney=nowMoney+drawingMoney;
            System.out.println(this.getName() + "手里的钱为:" + nowMoney);
        }

    }
}


}

不安全的集合添加 比实际添加的要少

###

添加同步块

package pyf.demo11;

import java.util.ArrayList;
import java.util.List;

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName UnSafeListDemo.java
 * @Description 线程不安全的集合
 * @createTime 2021年07月27日 11:39:00
 */
public class UnSafeListDemo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        for (int i = 0; i < 99999; i++) {

            new Thread(() -> {
                synchronized (list) {
                    list.add(Thread.currentThread().getName());
                }
            }).start();

        }
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

image.png

image.png

image.png

image.png
package pyf.demo12;

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName DeadLockDemo.java
 * @Description 避免死锁示例 避免资源相互调用
 * 注释部分为错误写法,造成死锁
 * @createTime 2021年07月27日 13:53:00
 */
public class DeadLockDemo {
    public static void main(String[] args) {
        new Use(0,"小明").start();
        new Use(1,"小红").start();
    }
/**
 * 资源一
 */
static class One{}

/**
 * 资源二
 */
static class Two{}

static class Use extends Thread{

     static One one=new One();
     static Two two=new Two();

     //选择
     int choice;
     //使用人
    String name;

    Use(int choice,String name){
        this.choice=choice;
        this.name=name;
    }
    private void startUse(){
        //if(0==choice){
        //    synchronized (one){
        //        System.out.println(this.name+"获得资源One");
        //        try {
        //            Thread.sleep(1000);
        //        } catch (InterruptedException e) {
        //            e.printStackTrace();
        //        }
        //        synchronized (two){
        //            System.out.println(this.name+"获取资源Two");
        //        }
        //    }
        //}else {
        //    synchronized (two){
        //        System.out.println(this.name+"获得资源two");
        //        try {
        //            Thread.sleep(2000);
        //        } catch (InterruptedException e) {
        //            e.printStackTrace();
        //        }
        //        synchronized (one){
        //            System.out.println(this.name+"获取资源one");
        //        }
        //    }
        //}
        if(0==choice){
            synchronized (one){
                System.out.println(this.name+"获得资源One");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            synchronized (two){
                System.out.println(this.name+"获取资源Two");
            }
        }else {
            synchronized (two){
                System.out.println(this.name+"获得资源two");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            synchronized (one){
                System.out.println(this.name+"获取资源one");
            }
        }
    }
    @Override
    public void run() {
        startUse();
    }
}
}

image.png

使用 ReentrantLock 可重复锁

package pyf.demo13;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName LockDemo.java
 * @Description 显示锁Lock用法
 * @createTime 2021年07月27日 14:17:00
 */
public class LockDemo {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        new Thread(buyTicket, "黄牛").start();
        new Thread(buyTicket, "小明").start();
        new Thread(buyTicket, "小红").start();
    }

    static class BuyTicket implements Runnable {

        int num = 10;
        boolean flag = true;
        ReentrantLock lock = new ReentrantLock();

        private void buy() {
            //模拟延时
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (num > 0) {
                System.out.println(Thread.currentThread().getName() + "购买票成功第" + num-- + "张票");
            } else {
                flag = false;
                return;
            }

        }

        @Override
        public void run() {
            while (flag) {
//官方建议放在try块中
                try {
                    lock.lock();
                    buy();
                } finally {
//解锁放在finally中
                    lock.unlock();
                }
            }
        }
    }
}

image.png

线程协作

生产者消费者模式

image.png

image.png

管程法

package pyf.gaoji;

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName TestPcDemo.java
 * @Description 生产者/消费者模式 -管程法
 * @createTime 2021年07月27日 16:06:00
 */
public class TestPcDemo {
    public static void main(String[] args) {
        Container container=new Container();
        new Product(container).start();
        new Consumer(container).start();
    }

//生产者
static class Product extends Thread{
    Container container;
    Product(Container container){
        this.container=container;
    }
    @Override
    public void run() {
        //批量放100只鸡
        for (int i = 0; i < 100; i++) {
            try {
                container.push(new Chiken(i));
                System.out.println("生产了"+i+"只鸡");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}
//消费者
static class Consumer extends Thread{
    Container container;
    Consumer(Container container){
        this.container=container;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                System.out.println("消费了"+container.pop().id+"只鸡");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


    }
}
//产品
static class Chiken{
    int id;
    public Chiken(int id) {
        this.id = id;
    }
}
//容器
static class Container{
    //计数器
    int num=0;
    //先定义容器大小,初始大小为10
    Chiken[] chikens=new Chiken[10];
    //放的方法,加入锁同步
    public synchronized void push(Chiken chiken) throws InterruptedException {
        //如果容器装满了则等待
        int cl= chikens.length;
        if(cl==num){
            this.wait();
        }
        chikens[num]=chiken;
        num++;
        //解除等待
        System.out.println(num);
        this.notifyAll();
    }
    //拿的方法,加入锁同步
    private synchronized Chiken pop() throws InterruptedException {
        //判断如果容器空了则等待生产者生产
        if(0== num){
            this.wait();
        }
        //取出产品
        num--;
        Chiken chiken = chikens[num];
        this.notifyAll();
        return chiken;
    }
}

}

标志法

package pyf.gaoji;

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName TestPcDemo2.java
 * @Description 生产者/消费者-标志法
 * @createTime 2021年07月27日 17:13:00
 */
public class TestPcDemo2 {
    public static void main(String[] args) {
        TV tv=new TV();
        new Shower(tv).start();
        new Watcher(tv).start();

    }

//生产者 演员
static class Shower extends Thread{
    TV tv;
    public Shower(TV tv){
        this.tv=tv;
    }
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                if(i%2==0){

                    tv.play("向往的生活");
                }else{
                    tv.play("快乐大本营");
                }
            }catch (Exception e){
                e.getMessage();
            }

        }
    }
}
//消费者 观众
static class Watcher extends Thread{
    TV tv;
    public Watcher(TV tv){
        this.tv=tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                tv.watch();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
//产品
static class TV{
    //节目名
    String programName;
    //标志
    boolean flag=true;
//表演方法
private synchronized void play(String programName) throws InterruptedException {
    if(!flag){
        this.wait();
    }
    this.programName=programName;
    this.flag=!this.flag;
    this.notifyAll();
    System.out.println("演员表演了"+programName);
}
//观看方法
private synchronized void watch() throws InterruptedException {
    if(flag){
        this.wait();
    }
    this.programName=programName;
    this.flag=!this.flag;
    this.notifyAll();
    System.out.println("观众观看了"+programName);
}
}
}
##使用java提供工具创建线程池
image.png
package pyf.gaoji;

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

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName ThreadPoolDemo.java
 * @Description 线程池
 * @createTime 2021年07月27日 17:48:00
 */
public class ThreadPoolDemo {

    public static void main(String[] args) {
        //阿里建议手动创建线程池
        //创建线程池
        ExecutorService service= Executors.newFixedThreadPool(10);

        //执行线程
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        //关闭连接
        service.shutdown();
    }
static class MyThread implements  Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
}

手动创建

package pyf.gaoji;

import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author pengyifeng
 * @version 5.1
 * @ClassName ManualThreadPool.java
 * @Description 手动创建线程池
 * @createTime 2021年07月27日 17:59:00
 */
public class ManualThreadPool {

    public static final Integer THREAD_POOL_SIZE=16;

    public static void main(String[] args) throws InterruptedException {
        ThreadFactory factory= new  ThreadFactoryBuilder().setNameFormat("hyn-demo-pool-%d").build();
        //创建线程池
        ThreadPoolExecutor executor= new ThreadPoolExecutor(THREAD_POOL_SIZE,THREAD_POOL_SIZE,0L, TimeUnit.MICROSECONDS,new LinkedBlockingDeque<>(1024),factory, new ThreadPoolExecutor.AbortPolicy());

        //执行
        for (int i = 0; i < 1000; i++) {
            executor.execute(()-> System.out.println(Thread.currentThread().getName()));
        }
        //关闭线程池
        executor.shutdown();
        executor.awaitTermination(1000L, TimeUnit.SECONDS);
        // 任务执行完毕后打印"Done"
        System.out.println("Done");
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容