多线程笔记以及案例总结

多线程详解

线程简介

  • 程序、进程、线程的关系
  1. 什么是线程:线程是程序中执行的线程 Java虚拟机允许程序同时运行多个执行线程。
  2. 进程:说起进程,就不得不说程序,程序是指令和数据得有序集合,其本身没有任何运行的意义,是一个静态的概念;而进程则是执行程序的一次执行过程,它是一个动态的概念。是系统资源分配的单位。
  3. 通常在一个进程中乐意包含若干个线程,当然一盒进程中至少有一个线程,不然没有存在的意义。线程是CPU调度和执行的单位、
  4. 线程就是独立执行路径。
  5. main()称之为主线程,为系统的入口,用于执行整个程序
  6. 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系系统紧密相关的,先后顺序不能人为干预。
  7. 对于同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制。
  8. 线程会带来额外的开销,如cpu调度时间,并发控制开销。
  9. 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致。

线程实现(重点)

1、继承Thread类
  1. 自定义线程类继承Thread类
  2. 重写run()方法,编写线程执行体
  3. 创建线程对象,调用start()方法启动线程
  • 不建议使用 避免OOP单继承局限性
//注意: 线程开启不一定立即执行 由cpu调度执行
public class ThreadDemo1 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println("线程for"+i);
        }
    }
}
class Test{
    public static void main(String[] args) {

        //创建线程对象
        ThreadDemo1 threadDemo1 = new ThreadDemo1();
        //调用start方法开启线程
        threadDemo1.start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("循环for"+i);
        }
    }
}
//网图下载  记得导入io-jar
package com.zhhl.thread;

import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;

public class ThreadDownLoad extends Thread {

    private String url; //图片的url地址
    private String name; //文件的名字

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

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

    }
    //主线程函数
    public static void main(String[] args) {

        ThreadDownLoad t1 = new ThreadDownLoad("http://img.netbian.com/file/2020/0828/small24f6fab40f7cb88c6ab720e5182bbe2f1598629198.jpg","01.jpg");
        ThreadDownLoad t2 = new ThreadDownLoad("http://img.netbian.com/file/2020/0820/smalla8c44abd984a8665ecec6a33cf709ec11597929475.jpg","02.jpg");
        ThreadDownLoad t3 = new ThreadDownLoad("http://img.netbian.com/file/2020/0818/small4769624e404775ab1f8e0ccdacb736711597684658.jpg","03.jpg");


        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }

}
//下载器
class WebDownload{
    //下载方法
    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异常");
        }

    }
}

2、实现Runnable接口
  1. 定义Runnable类实现Runnable接口
  2. 实现run()方法,编写线程执行体
  3. 创建线程对象,调用start()启动线程
  • 推荐使用,避免了单继承局限性,灵活方便,方便同一个对象被多个线程使用
public class RunnableDemo implements Runnable {
    //线程执行体
    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {
            System.out.println("线程======="+i);
        }
    }

    public static void main(String[] args) {

        //创建Runable接口的实现类对象
        RunnableDemo runnableDemo = new RunnableDemo();

        //创建线程对象 对象线程对象来开启我们的线程
//        Thread thread = new Thread(runnableDemo);
//        thread.start();
        new Thread(runnableDemo).start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("主线程---"+i);
        }

    }
}
//图片下载
package com.zhhl.thread;

import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;

public class RunnableDownLoad implements Runnable {

    private String url;
    private String name;

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

    @Override
    public void run() {
        WebDownLoader webDownLoader = new WebDownLoader();
        webDownLoader.downLoad(url,name);
        System.out.println("下载文件的名字:"+name);
    }

    //主函数
    public static void main(String[] args) {

        //创建实现类对象
        RunnableDownLoad r1 = new RunnableDownLoad("http://img.netbian.com/file/2020/0828/small24f6fab40f7cb88c6ab720e5182bbe2f1598629198.jpg","01.jpg");
        RunnableDownLoad r2= new RunnableDownLoad("http://img.netbian.com/file/2020/0820/smalla8c44abd984a8665ecec6a33cf709ec11597929475.jpg","02.jpg");
        RunnableDownLoad r3 = new RunnableDownLoad("http://img.netbian.com/file/2020/0818/small4769624e404775ab1f8e0ccdacb736711597684658.jpg","03.jpg");

        //创建线程对象并启动线程
        new Thread(r1).start();
        new Thread(r2).start();
        new Thread(r3).start();
    }
}

//下载器
class WebDownLoader{
    public void downLoad(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {
            System.out.println("IO异常");
        }

    }

}
3、实现Callable接口
  1. 实现Callable接口,需要返回值类型
  2. 重写call方法,需要抛出异常
  3. 创建目标对象
  4. 创建执行服务 ExecutorService e= Executors.newFixedThreadPool(3);
  5. 提交执行 Future s1 = e.submit(r1);
  6. 获取结果 boolean rs1 = s1.get();
  7. 关闭服务 e.shutdownNow();
package com.zhhl.thread;

import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.*;

public class CallableDemo implements Callable<Boolean> {

    private String url;
    private String name;

    public CallableDemo(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 {

        //创建实现类对象
        CallableDemo r1 = new CallableDemo("http://img.netbian.com/file/2020/0828/small24f6fab40f7cb88c6ab720e5182bbe2f1598629198.jpg","01.jpg");
        CallableDemo r2= new CallableDemo("http://img.netbian.com/file/2020/0820/smalla8c44abd984a8665ecec6a33cf709ec11597929475.jpg","02.jpg");
        CallableDemo r3 = new CallableDemo("http://img.netbian.com/file/2020/0818/small4769624e404775ab1f8e0ccdacb736711597684658.jpg","03.jpg");

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

        //提交执行
        Future<Boolean> s1 = e.submit(r1);
        Future<Boolean> s2= e.submit(r2);
        Future<Boolean> s3 = e.submit(r3);

        //获取结果
        boolean rs1 = s1.get();
        boolean rs2 = s2.get();
        boolean rs3 = s3.get();

        System.out.println(rs1);
        System.out.println(rs2);
        System.out.println(rs3);

        //关闭服务
        e.shutdownNow();

    }
}


//下载器
class WebDownLoad{
    public void downLoad(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        } catch (IOException e) {

            System.out.println("IO异常");
        }

    }

}
4、初识并发问题
//多个线程操作同一份资源的情况下,线程不安全,数据紊乱
public class ConcurrentDemo implements Runnable {
    private int ticket_num=10;

    @Override
    public void run() {
        while (true){
            if (ticket_num<=0){
                break;
            }
            //模拟延时
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"拿到了第"+ticket_num--+"张票");
        }

    }

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

//龟兔赛跑案例
public class Race implements Runnable {

    //胜利者
    public static String winner;
    @Override
    public void run() {
        for (int i = 0; i <= 100; i++) {
            
            //模拟兔子休息
            if (Thread.currentThread().getName().equals("兔子") && i%10==0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //判断比赛是否结束
            boolean flag = gameOvers(i);
            //如果比赛结束就停止程序
            if (flag){
                break;
            }

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

    }

    //判断比赛是否结束

    public boolean gameOvers(int stemp){
       //判断是否有胜利者
        if(winner!=null){
            return true;
        }else {
            if (stemp>=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();
    }
}
5、静态代理
package com.zhhl.thread;

//真实对象和带理对象都要实现同一个接口
    //代理对象要代理真实角色
    //代理对象可以做真实对象做不了的事情
    //真实对象专注于自己的事情
public class StaticPorxy {

    public static void main(String[] args) {

//        WeddingCompany weddingCompany = new WeddingCompany(new You());//你要结婚 传you对象 YOU you = new You();
//        weddingCompany.happrMarry();
        new Thread(()-> System.out.println("我爱你")).start(); //对比  happrMayyr()相当于线程里的start()
        new WeddingCompany(new You()).happrMarry(); //上面两句的整合
    }
}

interface Marry{
    void happrMarry();
}

//真实角色
class You implements Marry{

    @Override
    public void happrMarry() {
        System.out.println("我要结婚了 好开心");
    }
}

//代理角色
class WeddingCompany implements Marry{

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

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

    @Override
    public void happrMarry() {
        before();
        this.target.happrMarry();//真实对象
        after();
    }

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

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

}
6、lamda
package com.zhhl.thread;

public class Lamda {
    //静态内部类
/*    static class Lover implements Love{

        @Override
        public void love(int a) {
            System.out.println("i love you"+a);
        }
    }*/

    public static void main(String[] args) {

        //局部内部类
      /*  class Lover implements Love{
            @Override
            public void love(int a) {
                System.out.println("i love you"+a);
            }
        }*/
//        Love love = new Lover();
//        love.love(2);

        //匿名内部类 通过接口实现
        Love love =new Love() {
            @Override
            public void love(int a) {
                System.out.println("i love you"+a);
            }
        };
        love.love(2);
    }


}
//定义接口
interface Love{
    void love(int a);
}

//外部实现类
/*
class Lover implements Love{

    @Override
    public void love(int a) {
        System.out.println("i love you"+a);
    }
}*/

//=====================================================================
//lamda简化
package com.zhhl.thread;

public class Lmada2 {
    public static void main(String[] args) {
        //lmada表达式简化
        Love love =  (int a)->{
            System.out.println("Iloveyou"+a);
        };
        love.love(520);

        //简化参数类型 多参数也可简化 用逗号隔开
        love = (a)->{
            System.out.println("Iloveyou2"+a);
        };
        love.love(521);

        //简化括号 多个参数则不行
        love = a->{
            System.out.println("Iloveyou3"+a);
        };

        love.love(522);

        //简化花括号  只有一行代码才可以简化 接口为函数式接口(接口只有一个方法)
        love = a-> System.out.println("Iloveyou4"+a);
        love.love(523);

    }
}

线程状态

在这里插入图片描述

package com.zhhl.thread;

//建议线程正常停止--->利用次数 不建议死循环
    //建议使用标识位 设置一个标识位
    //不要使用stop后者destory过时的以及JDK不建议使用的方法
public class ThreadStop implements Runnable {

    //设置一个标识位
    private boolean flag = true;

    @Override
    public void run() {
        int i=0;
        while (flag){
            System.out.println("run ===thread"+i++);
        }
    }

    //设置一个公开的方法停止线程 转换标识位
    public void stop(){
        this.flag = false;
    }

    public static void main(String[] args) {
        ThreadStop threadStop = new ThreadStop();
        new Thread(threadStop).start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("main"+i);
            if (i==900){
                threadStop.stop();
                System.out.println("线程该停止了");
            }
        }
    }
}

线程方法
  1. setPriority(int newPriority) 更改线程的优先级
  2. static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠
  3. void join() 等待该线程终止
  4. static void yield() 暂停当前正在执行的线程对象,并执行其他线程
  5. void interrupt() 中断线程 别用这个方式
  6. boolean isAlive() 测试是否处于活动状态
线程休眠
  1. sleep(时间) 指定当前线程阻塞的毫秒数
  2. sleep存在InterruptedException;
  3. sleep时间达到后线程进入就绪状态
  4. sleep可以模拟网络延时
  5. 每一个对象都有一个锁,sleep不会释放锁
//模拟倒计时
public class ThreadSleep {

    public static void main(String[] args) {
        testTime();
    }
    public static void testTime(){
        int i = 10;
        while (true){
            try {
                Thread.sleep(1000); //每一秒打印一次
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(i--);
            if (i<0){ break;
            }
        }

    }
}

//打印当前时间
//打印当前时间
    public static void main(String[] args) {

        Date startTime = new Date(System.currentTimeMillis());//获取系统当前时间
        while (true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("YY:mm:ss").format(startTime));
                startTime = new Date(System.currentTimeMillis());//更新时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }


    }
线程礼让
  1. 礼让线程,让当前正在执行的线程暂停 ,但不阻塞,将线程从运行状态转为就绪状态
  2. 让cpu重新调度,礼让有时候不会成功
package com.zhhl.thread;

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()+"线程执行");
    }
}
合并线程
  1. join合并线程,待此线程执行完后,再执行其他线程
  2. 可以想象成插队
package com.zhhl.thread;

public class ThreadJoin implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 200; i++) {

            System.out.println("线程vip来了"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ThreadJoin threadJoin = new ThreadJoin();
        Thread thread = new Thread(threadJoin);


        for (int i = 0; i < 500; i++) {
            if (i==100){
                thread.start();
                thread.join();//插队
            }
            System.out.println("主线程"+i);

        }
    }
}

线程状态
  1. NEW 尚未启动的线程处于此状态
  2. RUNNABLE 在java虚拟机中执行的线程处于此状态
  3. BLOCKED 被阻塞等待监视器锁定的线程处于此状态
  4. WAITING 正在等待另一个线程执行特定动作的线程处于此状态
  5. TIMED_WAITING 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态
  6. TERMINATED 已退出的线程处于此状态
package com.zhhl.thread;

public class ThreadState {

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(500);
                } 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);//Run


        while (state != Thread.State.TERMINATED){ //只要线程不终止 就一直输出状态
            Thread.sleep(100);
            thread.getState();//更新线程状态
            System.out.println(state);
        }

    }

}

守护线程
  1. 线程分为用户线程合守护线程
  2. 虚拟机必须确保用户线程执行完毕
  3. 虚拟机不用等待守护线程执行完毕
  4. 如,后台记录操作日志,监控内存,垃圾回收等
package com.zhhl.thread;

//守护线程
public class ThreadDeamo {
    public static void main(String[] args) {
        Yous yous = new Yous();
        God god = new God();

        Thread thread = new Thread(god);
        thread.setDaemon(true); //默认为false 表示是用户线程 正常的线程都是用户线程
        thread.start(); //god守护线程
        new Thread(yous).start(); //你 用户线程停止

    }

}


class God implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println("上帝守护着你");
        }

    }
}


//你
class Yous implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("用心活好每一天");
        }
        System.out.println("++byebye++============================");
    }
}

线程同步

synchronized关键字

  1. 可分为同步方法跟同步块
  2. 同步方法:public synchronized void buy() {}
  3. 同步块:sunchronized(对象){} 默认锁的是this 正确应该锁执行增删改查的对象 也就是锁的变化的量
//案例
//方法锁
package com.zhhl.thread;

//线程不安全  synchronized可使变为安全
public class UnsafeBuyTicket {
    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){
            try {
                buy();
                //模拟延时
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


    }

    public synchronized void buy() {
        //判断是否有票
        if (ticketNums<=0){
            flag = false;
            return;
        }

        //买票
        System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);


    }
}

//案例二
//同步块
package com.zhhl.thread;

//不安全取钱
public class UnsafeBank {

    public static void main(String[] args) {
        Account account = new Account(100,"结婚基金");
        Drawing you = new Drawing(account,50,"你");
        Drawing youGirl = new Drawing(account,100,"youGirl");
        you.start();
        youGirl.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;
    }

    @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);
            //Thread.currentThread().getName() = this.getName();
            System.out.println(this.getName()+"手里的钱"+nowMoney);
        }

    }
}
JUC安全集合测试
package com.zhhl.thread;

import java.util.concurrent.CopyOnWriteArrayList;
//JU安全类型集合测试
public class TestJUC {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                copyOnWriteArrayList.add(Thread.currentThread().getName());
            }).start();
        }
		
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(copyOnWriteArrayList.size());
    }
}

死锁

产生死锁的四个必要条件

  1. 互斥条件:一个资源每次只能被一个进程使用
  2. 请求与保持条件:一个进程因请求在资源而阻塞时,对以获得的资源保持不放
  3. 不剥夺条件:进程以获得的资源,在未使用完之前,不能强行剥夺
  4. 循环等待条件:若干进程之前形成首尾相接的循环等待资源关系
//死锁案例
package com.zhhl.thread;

public class DeadLock {
    public static void main(String[] args) {
        Makeup makeup = new Makeup(0,"灰姑娘");
        Makeup makeup2 = new Makeup(1,"白雪公主");

        makeup.start();
        makeup2.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() {
        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(2000);//两秒后想获得口红的锁
                synchronized (lipstick){//口红的锁
                    System.out.println(this.girlName+"获取镜子的锁");
                }
            }

        }
    }
}
lock锁
  1. lock是显示锁 手动开启和关闭 ,synchronized是隐式锁,出了作用域自动释放

  2. lock只有代码块锁

  3. 使用lock锁,JVM将花费较少的时间来调度线程,性能更好,并且有良好的可扩展性

  4. 优先使用顺序:Lock >同步代码块(已经进入了方法体 ,分配了相应资源)> 同步方法(在方法体之外)

  5. 定义可重入锁:
    private final ReentrantLock reentrantLock = new ReentrantLock();

package com.zhhl.thread;

import java.util.concurrent.locks.ReentrantLock;

public class Lock {
    public static void main(String[] args) {
        TestLock testLock = new TestLock();
        new Thread(testLock,"小明").start();
        new Thread(testLock,"小红").start();
        new Thread(testLock,"小王").start();
    }
}

class TestLock implements Runnable{

    int ticketNums = 10;
    //定义可重入锁
    private final ReentrantLock reentrantLock = new ReentrantLock();

    @Override
    public void run() {
        while (true){
            try {
                reentrantLock.lock();//加锁
                if (ticketNums>0){
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+ticketNums--);
                }else {
                    break;
                }
            }finally {
                reentrantLock.unlock();//解锁
            }

        }

    }
}

线程通信问题

信号灯法
package com.zhhl.thread;

//信号灯法
public class TestPc {
    public static void main(String[] args) {
        TV tv = new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }

}

//生产者演员
class Player extends Thread{
    TV tv;
    public Player(TV tv){
        this.tv = tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if (i%2==0){
                this.tv.play("快乐大本营");
            }else{
                this.tv.play("抖音");
            }
        }
    }
}
//消费者-观众
class Watcher extends Thread{
    TV tv;
    public Watcher(TV tv){
        this.tv = tv;
    }

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

//产品 -节目
class TV{
    //演员表演  观众等待
    //观众观看 演员等待

    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.zhhl.thread;


import java.util.concurrent.ExecutorService;
import java.util.concurrent.*;

public class TestPool {
    public static void main(String[] args) {
        //创建服务  创建线程池
        //参数为线程池大小
        ExecutorService es = Executors.newFixedThreadPool(10);

        //执行
          es.execute(new MyThread());
          es.execute(new MyThread());
          es.execute(new MyThread());
          es.execute(new MyThread());


          //关闭连接
        es.shutdown();
    }
}


class MyThread implements Runnable{
    @Override
    public void run() {

        System.out.println(Thread.currentThread().getName());
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值