多线程详解

一、线程是什么?

在这里插入图片描述

二、使用

1.创建线程的方式

在这里插入图片描述
1.1继承Thead类,重写run方法

package org.example.Thread;
//创建线程方式一:继承Thread类,重写run方法,调用start开启线程
//线程开启不一定立即执行,由CPU调度执行
public class ThreadTest01 extends Thread{
    @Override
    public void  run(){
        for (int i = 0;i<20;i++){
            System.out.println("i am looking code--");
        }

    }

    public static void main(String[] args) {
        //创建线程对象
        ThreadTest01 threadTest01=new ThreadTest01();
        //开启线程
        threadTest01.start();
        for (int i = 0;i<200;i++){
            System.out.println("i am learning thread---");
        }
    }
}

第一种方法的实例,使用commons.io包下载网络图片,需要传入图片的url地址

package org.example.Thread;


import org.apache.commons.io.FileUtils;

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

//创建线程方式一:继承Thread类,重写run方法,调用start开启线程
//线程开启不一定立即执行,由CPU调度执行
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() {
        WebDownloader webDownloader=new WebDownloader();
        webDownloader.downloader(url,name);
        System.out.println("下载文件名为:"+name);

    }

    public static void main(String[] args) {
        ThreadTest02 t1=new ThreadTest02("https://image.baidu.com/search/detail?ct=503316480&z=undefined&tn=baiduimagedetail&ipn=d&word=NBA&step_word=&ie=utf-8&in=&cl=2&lm=-1&st=undefined&hd=undefined&latest=undefined&copyright=undefined&cs=2932802967,3528389954&os=2432392431,2252291014&simid=4242616644,652387190&pn=1&rn=1&di=5500&ln=1214&fr=&fmq=1616121336734_R&fm=&ic=undefined&s=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&is=0,0&istype=0&ist=&jit=&bdtype=0&spn=0&pi=0&gsm=0&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%253A%252F%252Fn.sinaimg.cn%252Fsinacn20122%252F648%252Fw724h724%252F20190106%252Fc232-hrfcctn3149191.jpg%26refer%3Dhttp%253A%252F%252Fn.sinaimg.cn%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Djpeg%3Fsec%3D1618713336%26t%3D5539acf22520b9c855e918c1b4674a70&rpstart=0&rpnum=0&adpicid=0&force=undefined&ctd=1616121338977^3_1905X929%1","1.jpg");
        ThreadTest02 t2=new ThreadTest02("https://image.baidu.com/search/detail?ct=503316480&z=undefined&tn=baiduimagedetail&ipn=d&word=NBA&step_word=&ie=utf-8&in=&cl=2&lm=-1&st=undefined&hd=undefined&latest=undefined&copyright=undefined&cs=2932802967,3528389954&os=2432392431,2252291014&simid=4242616644,652387190&pn=1&rn=1&di=5500&ln=1214&fr=&fmq=1616121336734_R&fm=&ic=undefined&s=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&is=0,0&istype=0&ist=&jit=&bdtype=0&spn=0&pi=0&gsm=0&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%253A%252F%252Fn.sinaimg.cn%252Fsinacn20122%252F648%252Fw724h724%252F20190106%252Fc232-hrfcctn3149191.jpg%26refer%3Dhttp%253A%252F%252Fn.sinaimg.cn%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Djpeg%3Fsec%3D1618713336%26t%3D5539acf22520b9c855e918c1b4674a70&rpstart=0&rpnum=0&adpicid=0&force=undefined&ctd=1616121338977^3_1905X929%1","2.jpg");
        ThreadTest02 t3=new ThreadTest02("https://image.baidu.com/search/detail?ct=503316480&z=undefined&tn=baiduimagedetail&ipn=d&word=NBA&step_word=&ie=utf-8&in=&cl=2&lm=-1&st=undefined&hd=undefined&latest=undefined&copyright=undefined&cs=2932802967,3528389954&os=2432392431,2252291014&simid=4242616644,652387190&pn=1&rn=1&di=5500&ln=1214&fr=&fmq=1616121336734_R&fm=&ic=undefined&s=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&is=0,0&istype=0&ist=&jit=&bdtype=0&spn=0&pi=0&gsm=0&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%253A%252F%252Fn.sinaimg.cn%252Fsinacn20122%252F648%252Fw724h724%252F20190106%252Fc232-hrfcctn3149191.jpg%26refer%3Dhttp%253A%252F%252Fn.sinaimg.cn%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Djpeg%3Fsec%3D1618713336%26t%3D5539acf22520b9c855e918c1b4674a70&rpstart=0&rpnum=0&adpicid=0&force=undefined&ctd=1616121338977^3_1905X929%1","3.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("IO异常");
        }
    }
}

1.2实现Runnable接口

package org.example.Thread;
//创建线程方式二:实现runnable接口,重写run方法,执行线程需要丢入runnable的结构实现类,调用start开启线程
//线程开启不一定立即执行,由CPU调度执行
public class ThreadTest03 implements Runnable{

    @Override
    public void run() {
        for (int i = 0;i<20;i++){
            System.out.println("i am looking code--");
        }
    }

    public static void main(String[] args) {
        ThreadTest03 threadTest03=new ThreadTest03();
        Thread thread=new Thread(threadTest03);
        thread.start();
        for (int i = 0;i<200;i++){
            System.out.println("i am learning thread---");
        }
    }
}

第二种方法的实例,实现龟兔赛跑,兔子线程使用sleep()方法模拟休息

package org.example.Thread;

//模拟龟兔赛跑
public class Race implements Runnable{
    private  String winner;
    @Override
    public void run() {
        for(int i=1;i<=100;i++){
            if(Thread.currentThread().getName().equals("兔子")&&i%10==0) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            boolean flag=gameover(i);
            if(flag) break;
            System.out.println(Thread.currentThread().getName()+"-->跑了"+i+"步");

        }


    }
    public  boolean gameover(int steps){
        if(winner!=null) {
            return  true;
        }
        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();
    }
}

两种方式的优缺点:
在这里插入图片描述

2.并发问题

模拟多个人买票

package org.example.Thread;
//发现问题:多个线程操作同一资源的情况下,线程不安全,数据紊乱      这就是并发问题
public class ThreadTest04 implements Runnable{
    private int ticketNums= 10;
    @Override
    public void  run(){
       while (true)
       {
           if (ticketNums<=0) break;;
           System.out.println(Thread.currentThread().getName()+"-->拿到第 "+ticketNums--+" 票");
       }

    }

    public static void main(String[] args) {

        ThreadTest04 t=new ThreadTest04();
        new Thread(t,"小明").start();
        new Thread(t,"老师").start();
        new Thread(t,"黄牛党").start();



    }
}

多个线程操作同一资源的情况下,线程不安全,数据紊乱,这就是并发问题
在这里插入图片描述

三、线程的常用方法

3.1测试停止线程

1.建议线程正常停止–>利用次数,不建议死循环
2.建议使用标志位–>设置一个标志位
3.不要使用stop或者destory方法,官方已经推荐不使用

package org.example.Thread;
//测试停止线程
//1.建议线程正常停止-->利用次数,不建议死循环
//2.建议使用标志位-->设置一个标志位
//3.不要使用stop或者destory方法
public class ThreadTest05 implements Runnable{
   private  boolean flag=true;
    @Override
    public void  run(){
        int i=0;
       while (flag)
       {

           System.out.println("run+"+i++);

       }

    }
    public void  stop(){
        this.flag=false;
    }

    public static void main(String[] args) {

        ThreadTest05 t=new ThreadTest05();
        new Thread(t).start();
        for(int i=0;i<1000;i++){
         System.out.println("main"+i);
            if(i==900){
                t.stop();
                System.out.println("stop the thread");
            }
        }




    }
}

3.2测试礼让线程

package org.example.Thread;
//测试礼让线程,礼让不一定成功,看CPU心情
public class ThreadTest06 implements Runnable{
   
    @Override
    public void  run(){
        System.out.println(Thread.currentThread().getName()+" start");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+" end");
    }

    public static void main(String[] args) {

        ThreadTest06 t=new ThreadTest06();
        new Thread(t,"a").start();
        new Thread(t,"b").start();




    }
}

测试礼让线程,礼让不一定成功,看CPU心情,结果不一样
礼让成功
在这里插入图片描述
礼让不成功
在这里插入图片描述

3.3测试join方法

join方法,想像为插队

package org.example.Thread;
//测试join方法,想像为插队
public class ThreadTest07 implements Runnable{
    
    @Override
    public void  run(){
      for (int i=0;i<1000;i++){
          System.out.println("线程VIP来了"+i);
      }

    }

    public static void main(String[] args) throws InterruptedException {

        ThreadTest07 t=new ThreadTest07();
        Thread thread = new Thread(t);
        thread.start();
        for (int i=0;i<500;i++){
            if(i==200) thread.join();//插队
             System.out.println("main "+i);
        }

 


    }
}

3.4测试线程的状态

在这里插入图片描述

在这里插入图片描述

package org.example.Thread;
//测试线程状态
public class ThreadTest08 {


    public static void main(String[] args) throws InterruptedException {

        Thread t=new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("/");
        });//使用lambda表达式
        Thread.State state=t.getState();
        System.out.println(state);
        t.start();
        state=t.getState();
        System.out.println(state);
        while (state!=Thread.State.TERMINATED)
        {
            Thread.sleep(100);
            state=t.getState();
            System.out.println(state);
        }





    }
}

四.并发问题解决

4.1线程同步

在这里插入图片描述
用synchronized 改写买票例子,这个例子 synchronized用来修饰方法

package org.example.Thread.syn;

import org.example.Thread.ThreadTest04;
//不安全
public class BuyTicket implements Runnable{
    private int ticketNums= 10;
    private boolean flag=true;
    @Override
    public void  run() {
        while (flag) {
            buy();
        }
    }
    public 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-- + " 票");
        return;
    }
    public static void main(String[] args) {

        BuyTicket t=new BuyTicket();
        new Thread(t,"小明").start();
        new Thread(t,"老师").start();
        new Thread(t,"黄牛党").start();



    }
}

数据同步
在这里插入图片描述
银行取钱例子,两个人取同一个账户,同样用 synchronized,而这个例子锁住对象,需要增删改的对象

package org.example.Thread.syn;
//不安全,两个人去银行取钱,账户
public class UnsafeBank {
    public static void main(String[] args) {
        Account account=new Account(100,"老婆本");
        Drawing drawing=new Drawing(account,50,"你");
        Drawing drawing1=new Drawing(account,100,"她");
        drawing.start();
        drawing1.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-=drawingMoney;
            nowMoney+=drawingMoney;
            System.out.println("余额为:"+account.money);
            System.out.println(this.getName()+"手里的钱"+nowMoney);

        }

    }
}

在这里插入图片描述

4.2lock

在这里插入图片描述
同样是刚才例子 用lock实现

package org.example.Thread.lock;

import org.example.Thread.ThreadTest04;

import java.util.concurrent.locks.ReentrantLock;

public class LockTest1 {
    public static void main(String[] args) {

        Test t=new Test();
        new Thread(t,"老师").start();
        new Thread(t,"小明").start();
        new Thread(t,"黄牛党").start();



    }
}

class Test implements Runnable{
    private int ticketNums= 10;
    //定义lock锁
    private  final ReentrantLock lock=new ReentrantLock();
    @Override
    public void  run(){
        while (true)
        {  try {
            lock.lock();

            if (ticketNums<=0) break;;
            System.out.println(Thread.currentThread().getName()+"-->拿到第 "+ticketNums--+" 票");
           }finally {
              lock.unlock();
           }


        }

    }
}

在这里插入图片描述

4.3死锁

在这里插入图片描述
死锁的例子

package org.example.Thread.lock;
//死锁
public class DeadLock {
    public static void main(String[] args) {
        Makeup g1=new Makeup(0,"beatuiful girl");
        Makeup g2=new Makeup(1,"ugly girl");
        g1.start();
        g2.start();
    }

}
//口红
class  Lipstick{

}
//镜子
class Mirror{

}
class  Makeup extends Thread {
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();
    int choice;//选择
    String girlName;//名字

    public Makeup(int choice, String girlName) {
        this.choice = choice;
        this.girlName = girlName;
    }

    @Override
    public void run() {
        try {
            makeup();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //化妆,互相持有对方的资源,就是需要拿到对方的资源
    private void makeup() throws InterruptedException {
        if (choice == 0) {
            synchronized (lipstick) {
                System.out.println(this.girlName + "获得口红的锁");
                Thread.sleep(1000);//一秒钟后获得镜子
                synchronized (mirror) {
                    System.out.println(this.girlName + "获得镜子的锁");
                }
            }
        }
        else {
            synchronized (mirror) {
                System.out.println(this.girlName + "获得镜子的锁");
                Thread.sleep(1000); //一秒钟后获得口红
                synchronized (lipstick) {
                    System.out.println(this.girlName + "获得口红的锁");
                }
            }

        }
    }
}

4.3生产者消费者模式

4.3.1管程法

生产者消费者模型–>利用缓冲区解决:管程法
生产着,消费者,产品,缓冲区

package org.example.Thread.lock;

public class TestPC {
    public static void main(String[] args) {
        SynContainer synContainer=new SynContainer();
        Productor productor=new Productor(synContainer);
        Consumer consumer=new Consumer(synContainer);
        productor.start();
        consumer.start();
    }
}

//生产者
class Productor extends Thread{
      SynContainer synContainer;

    public Productor(SynContainer synContainer) {
        this.synContainer = synContainer;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {

            synContainer.push(new Chicken(i));
            System.out.println("生产了第"+i+"只鸡");
        }
    }
}
//消费者
class Consumer extends Thread{
    SynContainer synContainer;

    public Consumer(SynContainer synContainer) {
        this.synContainer = synContainer;
    }
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了第"+ synContainer.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;
        this.notify();
    }
    //消费者消费产品
    public  synchronized  Chicken pop(){
        if(count==0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
         count--;
        Chicken chicken=chickens[count];
        this.notify();
        return chicken;
    }
}

4.3.2信号灯法

package org.example.Thread.lock;
//信号灯法
public class TestPC1 {
    public static void main(String[] args) {
        NBA nba=new NBA();
        new Player(nba).start();
        new Watcher(nba).start();
    }
}
class  Player extends Thread{
    NBA nba;

    public Player(NBA nba) {
        this.nba = nba;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if(i%2==0) this.nba.play("爵士");
            else  this.nba.play("湖人");
        }
    }
}
class Watcher extends Thread{
    NBA nba;

    public Watcher(NBA nba) {
        this.nba = nba;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            this.nba.watch();
        }

    }
}
class  NBA{
    String name;
    boolean flag=true;
    public  synchronized void play(String name){
        if(!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("球员进行了"+name+"的比赛");
        this.notifyAll();
        this.name=name;
        this.flag=!this.flag;
    }
    public  synchronized void watch(){
        if(flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("观众观看了"+name+"的比赛");
        this.notifyAll();
        this.flag=!this.flag;
    }
}

4.4线程池

在这里插入图片描述

package org.example.Thread.lock;

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

public class PoolTest {
    public static void main(String[] args) {
        //1.创建服务,创建线程池
        //newFixedThreadPool 参数为:线程池大小
        ExecutorService executorService= Executors.newFixedThreadPool(10);
        executorService.execute(new MyThred());
        executorService.execute(new MyThred());
        executorService.execute(new MyThred());
        executorService.execute(new MyThred());
       //2.关闭连接
        executorService.shutdown();
    }
}
class MyThred implements Runnable{
    @Override
    public void run() {

            System.out.println(Thread.currentThread().getName());

    }
}

在这里插入图片描述

五.Lambda表达式

定义函数式接口:任何接口只包含一个抽象方法

package org.example.Lambda;

public class LambdaTest1 {
    //3.静态内部类
   static class YouHot2 implements Hot{
        @Override
        public void lambda() {
            System.out.println("i am hot2");
        }
    }
    public static void main(String[] args) {
        Hot youhot=new YouHot();
        youhot.lambda();
        youhot=new YouHot2();
        youhot.lambda();
        //4.局部内部类
        class YouHot3 implements Hot{
            @Override
            public void lambda() {
                System.out.println("i am hot3");
            }
        }
        youhot=new YouHot3();
        youhot.lambda();
       //5.匿名内部类,没有类的名称,必须借助接口或者父类
        youhot=new Hot() {
            @Override
            public void lambda() {
                System.out.println("i am hot4");
            }
        };
       youhot.lambda();
       //用lambda简化
        youhot=() ->{
            System.out.println("i am hot5");
        };
        youhot.lambda();
    }
}
//定义一个函数式接口:任何接口只包含一个抽象方法
interface Hot{
    void  lambda();
}
class YouHot implements Hot{
    @Override
    public void lambda() {
        System.out.println("i am hot");
    }
}
package org.example.Lambda;

public class Test2 {
    public static void main(String[] args) {
         Hot1 hot=(String name)->{
             System.out.println(name+" is hot");
         };
         //简化参数类型
        hot=(name)->{
            System.out.println(name+" is hot");
        };
        //简化括号
        hot=name->{
            System.out.println(name+" is hot");
        };
        //简化花括号
        hot=name->System.out.println(name+" is hot");
         hot.lambda("jay");
    }
}
interface Hot1{
    void  lambda(String name);
}
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhixuChen200

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值