关于多线程

多线程

线程实现和线程同步(重点)

程序

静态的概念,用逻辑处理数据

进程

是程序执行一次执行过程,是一个动态的概念.是系统资源分配的单位

线程

一个进程至少有一个线程,比如main,线程是并发执行.是CPU调度和执行的单位


注意:

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

线程核心概念

  • 线程就是独立的执行路径

  • 在程序运行时,即是没有自己创建线程,后台也会有多个线程,如主线程,gc线程

  • main()称之为主程序,为系统的入口,用于执行整个程序

  • 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的

  • 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制

  • 线程会带来额外的开销,如cpu调度时间,并发控制开销

  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ayqsi37R-1637922287678)(C:\Users\74771\AppData\Roaming\Typora\typora-user-images\1636276800355.png)]

继承Thread类创建线程

  • 创建线程,继承thread类
  • 重写run()方法
  • 调用start开启线程

总结:注意,线程开启不一定立即执行,由CPU调度执行

体会run()和start()的不同

public class ThreadDemo01 extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("冷月葬花魂"+i);
        }
    }

    public static void main(String[] args) {
        ThreadDemo01 threadDemo01 = new ThreadDemo01();
      //  threadDemo01.run();
        threadDemo01.start();
        for (int i = 0; i < 200; i++) {
            System.out.println("寒塘渡鹤影"+i);
        }
    }
}

网络资源下载

需要导入 commons-io-2.11.0 包

import org.apache.commons.io.FileUtils;

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

public class WebDownMain extends Thread{
    private String url;
    private String name;

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

    @Override
    public void run() {
        Down down = new Down();
        down.down(url,name);
        System.out.println(name+"下载好了");
    }

    public static void main(String[] args) {
        WebDownMain webDownMain = new WebDownMain("https://m701.music.126.net/20211110173708/3174f994aadd0570b384b0c4d21b6980/jdyyaac/535d/0e0e/030e/d79981c8139db5e873324d6c6839ecde.m4a","枉凝眉.m4a");
        webDownMain.start();
    }
}
class Down{
    public void down(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        }
        catch (Exception e){

        }
    }
}

线程创建的三种方法

public class ThreadNew {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 一种
        new MyThread1().start();
        //第二种
        new Thread(new MyThread2()).start();
        //第三种

        FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3());
        new Thread(futureTask).start();

        Integer integer = futureTask.get();
        System.out.println(integer);


    }

}

class MyThread1 extends Thread{
    @Override
    public void run() {
        System.out.println("1111");
    }
}

class MyThread2 implements Runnable{
    @Override
    public void run() {
        System.out.println("2222");
    }
}
class MyThread3 implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("333");
        return 100;
    }
}

并发

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

买火车票
发现问题
多个线程操作同一个资源的情况下 ,线程不安全 ,数据紊乱
public class TsetThread implements  Runnable{
private  int ticketNums = 10;
    @Override
    public void run() {
        while(ticketNums>0){
           // if(ticketNums<=0){
                System.out.println(Thread.currentThread().getName()+"--拿到了"+ticketNums+"票");
                   ticketNums--;
          //  }
        }
    }
    public static void main(String[] args) {
        TsetThread tsetThread = new TsetThread();
        new Thread(tsetThread,"小明").start();
        new Thread(tsetThread,"老师").start();
        new Thread(tsetThread,"黄牛党").start();
    }
}

龟兔赛跑

public class Race implements Runnable {

    private 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(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            if (gameOver(i)) {
                break;
            }

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

    private 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();
    }
}

实现Callable接口

Callable的好处

  • 可以定义返回值
  • 可以抛出异常
  • 四步走
  • 在线程池中
        1.  //创建执行服务
    ExecutorService ser = Executors.newFixedThreadPool(2);
    2 //提交执行

     Future<Boolean> submit1 = ser.submit(webDownMain1);
        java.util.concurrent.Future<Boolean> submit2 = ser.submit(webDownMain2);
       // Future<Boolean> r2 = ser.submit(webDownMain2);

       3 //获取结果
        boolean rs1 = submit1.get();
        boolean rs2 = submit2.get();

       4 //关闭服务
        ser.shutdownNow();
    
package com.kuang.lesson01;

import com.sun.corba.se.impl.orbutil.closure.Future;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.net.URL;
import java.util.concurrent.*;
public class down implements Callable <Boolean> {
    private String url;
    private String name;

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

    @Override
    public Boolean call() {
        Down down = new Down();
        down.down(url,name);
        System.out.println(name+"下载好了");
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        down webDownMain1 = new down("https://m701.music.126.net/20211110173708/3174f994aadd0570b384b0c4d21b6980/jdyyaac/535d/0e0e/030e/d79981c8139db5e873324d6c6839ecde.m4a","枉凝眉.m4a");
        down webDownMain2 = new down("https://m701.music.126.net/20211110173708/3174f994aadd0570b384b0c4d21b6980/jdyyaac/535d/0e0e/030e/d79981c8139db5e873324d6c6839ecde.m4a","枉凝眉.m4a");

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


        //提交执行

     Future<Boolean> submit1 = ser.submit(webDownMain1);
        java.util.concurrent.Future<Boolean> submit2 = ser.submit(webDownMain2);
       // Future<Boolean> r2 = ser.submit(webDownMain2);

        //获取结果
        boolean rs1 = submit1.get();
        boolean rs2 = submit2.get();

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


class Down{
    public void down(String url,String name){
        try {
            FileUtils.copyURLToFile(new URL(url),new File(name));
        }
        catch (Exception e){

        }
    }
}



静态代理
  • 真实对象和代理对象都要实现同一个接口
  • 代理对象要代理真实角色
  • 好处:
    - 代理对象可以做很多真实对象做不了的事情
    - 真实对象专注于做自己的事情
new WeddingCompany(new You()).happyMarry();
new Thread(new Runnable() @Override public void run() { }}).start();
两行代码实际上差不多
    //即线程和 静态代理之间的关系

public class StaticProxy {
    public static void main(String[] args) {
        new WeddingCompany(new You()).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();
        target.happyMarry();
        after();
    }
    public void before(){
        System.out.println("结婚前,布置现场");
    }
    public void after(){
        System.out.println("结婚后,收尾款");
    }
}

lambda 表达式

总结:

  • lambda表达式只能有一行代码的情况下才能简化为一行,如果有多行,就要用代码块{}包裹

  • 前提是接口为函数式函数(里面只有一个方法)

  • 多个参数也可以去掉参数类型,要去都去,必须加括号

  • ILike like4 = (7,8)(参数数值)-> System.out.println(“i like lambda 7”+a);

package com.kuang.lesson01;

public class lambdaTest {
    // 静态内部类,在类中
    static class like2 implements ILike{
        @Override
        public void lambda() {
            System.out.println("i like lambda1");
        }
    }

    public static void main(String[] args) {
           // 局部内部类, 在方法中
        class like implements ILike{
            @Override
            public void lambda() {
                System.out.println("i like lambda2");
            }
        }
        like2 like2 = new like2();
        like like = new like();

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

        //lambda 表达式
        ILike like4 = ()->{ System.out.println("i like lambda6");};

        //再精简,括号和花括号都可以去掉
        like4 = ()-> System.out.println("i like lambda 7");
        
        //如果有参数
        //  ILike  like4 = (7,8)(参数数值)-> System.out.println("i like lambda 7"+a);

        // 总结:lambda表达式只能有一行代码的情况下才能简化为一行,如果有多行,就要用代码块{}包裹
        //前提是接口为函数式函数(里面只有一个方法)
        //多个参数也可以去掉参数类型,要去都去,必须加括号
        
        like.lambda();
        like2.lambda();
        like3.lambda();
    }
}

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

线程停止 stop
public class stopTest implements Runnable{
    private boolean flag = true;
    @Override
    public void run() {
        int i=0;
        while(flag){
            System.out.println("run...thread"+i++);
        }
    }
    public void stop(){
        flag = false;
    }
    public static void main(String[] args) {
        stopTest stopTest = new stopTest();
        new Thread(stopTest).start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("main" + i);
            if(i==998){
                stopTest.stop();
            }
        }
    }
}


线程休眠 sleep
  • 模拟倒计时

  • ,每个对象都有一个锁,sleep 不会释放锁

  • 项目经理要求这里运行缓慢,好让客户给钱优化, 并得到明显的速度提升

    Thread.sleep(1000);

import java.text.SimpleDateFormat;
import java.util.Date;
public class TestSleep {
    //还可以打印系统时间
    public static void main(String[] args) throws InterruptedException {
        Date data = new Date(System.currentTimeMillis());
        while(true){
                Thread.sleep(1000);
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(data));//获取时间
            data = new Date(System.currentTimeMillis());//更新时间
        }
        // tenDown();
    }
    public static void tenDown() throws InterruptedException {
          int num = 10;
          while (true){
                Thread.sleep(1000);
              System.out.println(num--);
              if(num<=0){
                  break;
              }
          }
    }
}


线程礼让 yeild
public class yeildTest {
    public static void main(String[] args) {
        MyYeild myYeild = new MyYeild();
        new Thread(myYeild,"A").start();
        new Thread(myYeild,"B").start();
    }
}
class MyYeild implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"线程开始执行");
        Thread.yield();//礼让
        System.out.println(Thread.currentThread().getName()+"线程结束执行");
    }


线程强制执行 join
  • 可以看做是插队
public class JoinTest 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 {
        JoinTest joinTest = new JoinTest();
        Thread th =  new Thread(joinTest);
        th.start();
        for (int i = 0; i < 500; i++) {
            if(i==50){
                th.join();
            }
            System.out.println("main"+i);
        }
    }

}

观测线程状态 state
  • new 尚未启动的线程处于此状态
  • runnable 在java虚拟机中执行的线程处于此状态
  • blocked 被阻塞等待监控器锁定的线程处于此状态, 等待CPU调度
  • waiting 正在等待另一个线程执行特定动作的线程处于此状态
  • time_waitting 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态
  • terminated 已退出的的线程处于此状态
public class TestState {
    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();//Run
        state = thread.getState();
        System.out.println(state);
        //只要线程不终止,就一直输出
        while(state != Thread.State.TERMINATED){
            Thread.sleep(1000);
            state  = thread.getState();//更新线程状态
            System.out.println(state);
        }
    }
}


线程的优先级 priority
public class PriorityTest {
    public static void main(String[] args) {
        //主线程默认优先级
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
        MyPriority myPriority = new MyPriority();
        Thread t1 = new Thread(myPriority);
        Thread t2 = new Thread(myPriority);
        Thread t3 = new Thread(myPriority);
        Thread t4 = new Thread(myPriority);
        //先设置优先级,再启动
        //优先级只在 1- 10 之间,其他会报错
        t1.start();
        t2.setPriority(1);
        t2.start();
        t3.setPriority(4);
        t3.start();
        t4.setPriority(Thread.MAX_PRIORITY);
        t4.start();
    }
}
class MyPriority implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());
    }
}

守护线程,daemon
public class DaemonTest {
    public static void main(String[] args) {
        God god = new God();
        You2 you2 = new You2();
        Thread thread = new Thread(god);
        thread.setDaemon(true);//默认是false表示是用户线程,正常的线程都是用户线程
        thread.start();//上帝守护线程启动
        new Thread(you2).start();// 你,用户线程启动
    }
}
class God implements Runnable{
    @Override
    public void run() {
        while(true){      //守护之后就会结束
            System.out.println("上帝保佑着你");
        }
    }
}
class You2 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("开心的活着");
        }
        System.out.println("===== goodbye world =====");
    }
}

线程同步

队列和锁机制(synchronized)
  • 性能和安全
  • 你上厕所,后面人要排队 = 队列
  • 上的时候要关门 = 锁 = 安全
不安全的取钱
//不安全取钱
//两个人去银行取钱,账户
public class UnsafeBank {
    public static void main(String[] args) {
        Account account = new Account(100,"结婚基金");
        Drawing you = new Drawing(account, 50, "你");
        Drawing girlFriend = new Drawing(account, 100, "grilFriend");
        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;
    }
    @Override
    public void run() {
        //判断有没有钱
        if(account.money-drawingMoney<0){
            System.out.println(this.getName()+"not money");
            return;
        }
        try {
            Thread.sleep(1000);
            //可以放大问题的发生性 ,      很重要,    不然看不出来
            
              // 等待两者同时取钱
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        account.money = account.money-drawingMoney;
        nowMoney = nowMoney +drawingMoney;
        // this.name = Thread.currentThread().getName(),因为继承了Thread类
        System.out.println(account.name+"余额为"+account.money);
        System.out.println(this.getName()+"手里的钱为"+nowMoney);
    }
}

安全形式
  • synchronized (account){}
  • 同步块
 public void run() {
        synchronized (account){
            //判断有没有钱
            if(account.money-drawingMoney<0){
                System.out.println(this.getName()+"not money");
                return;
            }
            try {
                Thread.sleep(1000);
                // 等待两者同时取钱
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            account.money = account.money-drawingMoney;
            nowMoney = nowMoney +drawingMoney;
            // this.name = Thread.currentThread().getName(),因为继承了Thread类
            System.out.println(account.name+"余额为"+account.money);
            System.out.println(this.getName()+"手里的钱为"+nowMoney);
        }

    }

出现负数

当票只剩一张,大家都要买了,所以出现负数,

  • 每个线程都有自己的工作内存
不安全的买票
//不安全的买票
//线程不安全,有负数
public class UnsafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        new Thread(buyTicket,"苦逼的我").start();
        new Thread(buyTicket,"牛逼的你们").start();
        new Thread(buyTicket,"可恶的黄牛党").start();
    }
}
class BuyTicket implements Runnable{
    private int ticketNums = 10;
    boolean flag = true;//外部停止方式
    @Override
    public void run() {
        while(flag){
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    private void buy() throws InterruptedException {
        //判断是否有票
        if (ticketNums<=0){
            flag = false;
            return;
        }
        //模拟延时
        Thread.sleep(1000);
        //买票
        System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
    }
}

  • 在 buy 方法前 加 锁就行了
  • private synchronized void buy()
  • 同步方法
private synchronized void buy() throws InterruptedException {
        //判断是否有票
        if (ticketNums<=0){
            flag = false;
            return;
        }
        //模拟延时
        //Thread.sleep(1000);
        //买票
        System.out.println(Thread.currentThread().getName()+"拿到"+ticketNums--);
    }

线程的不安全

最后加不到1000

import java.util.ArrayList;
public class UnsafeList {
    public static void main(String[] args) throws InterruptedException {
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        //Thread.sleep(2000);
        System.out.println(list.size());
    }
}




//不同的包 juc


public class TestCallable {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<String>();
        for (int i = 0; i < 1000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        System.out.println(list.size());
    }
}


synchronized

  • 锁要变化的量
  • 即增删改查的量

死锁

死锁线程各自占有一些共享资源,并且相互等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形,某一个同步块同时拥有两个以上对象的锁 时就可能会发生 死锁的问题

两个孩子都有玩具,但想抢另一个的,就都卡了,(人不会,但机器会)

  • 我口红,你镜子,都想拿对方的,两个进程都想要镜子

产生死锁的四个必要条件


  1. 互斥条件 : 一个资源每次只能被一个进程使用
  2. 请求与保持条件 : 一个进程因请求资源而阻塞时,对方获得的资源保持不放
  3. 不剥夺条件: 进程已获得的资源,在未使用完之前,不能强行剥夺
  4. 循环等待条件 : 若干进程之间形成一种头尾相接的循环等待资源关系
public class DeadLock {
    public static void main(String[] args) {
        Makeup g1 = new Makeup(0,"灰姑娘");
        Makeup g2 = new Makeup(0,"白雪公主");
        g1.start();
        g2.start();
    }
}

class Lipsticl{
}
class Mirror{
}

class Makeup extends Thread{
    //需要的资源只有一份,用static 来保证只有一份
    static Lipsticl lipsticl = new Lipsticl();
     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 (lipsticl) {
                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 (lipsticl) {
                    System.out.println(this.girlname + "获得口红的锁");
                }
            

        }
        //放到else 外面就不会死锁了

    }
}


Lock

ReentrantLock lock = new ReentrantLock();

lock.lock();//加锁

lock.unlock();

public class LockTest {
    public static void main(String[] args) {
        Testlock2 testlock2 = new Testlock2();
        new Thread(testlock2).start();
        new Thread(testlock2).start();
        new Thread(testlock2).start();
    }
}
class Testlock2 implements Runnable{

    int ticketNums = 10;
    //定义lock锁
    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();
                }
            }
            }
        }


Lock 和 synchronized的对比
  • Lock 是显式锁( 手动开启和关闭锁,别忘记关闭锁) synchronized 是隐式锁,出了作用域自动释放
  • Lock只有代码块 synchronized有代码块锁和方法锁
  • 使用Lock锁 ,JVM将花费较少的时间来调度线程,性能更好.并且具有更好的扩展性,( 提供更多的子类 )
  • 优先使用顺序:

​ - Lock >同步代码块 ( 已经进入了方法体 ,分配了相应资源) > 同步方法 (在方法体之外)

生产者与消费者问题

利用缓冲区解决 : 管程法

注意 this.notify() 和 this.wait(); 的使用

//测试  :生产者消费者模型 --> 利用缓冲区解决 : 管程法

//生产者  , 消费者  , 产品  , 缓冲区
public class TestPC {
    public static void main(String[] args) {
        SynContainer container = new SynContainer();
        new Productor(container).start();
        new Consumer(container).start();
    }
}
class Productor extends Thread{
    SynContainer container;
    public Productor(SynContainer container) {
        this.container = container;
    }
       //生产
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("生产了"+i+"只鸡");
            try {
                container.push(new Chicken(i));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class Consumer extends Thread{
    SynContainer container;

    public Consumer(SynContainer 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();
            }
        }
    }
}
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) throws InterruptedException {

        //如果容器满了,就等待消费者消费
        if(count == chickens.length){
            //通知消费者消费,生产者等待
                 this.wait();
        }
        //如果没有满,我们就需要丢入产品
        chickens[count] = chicken;
        count++;
        //可以通知消费者消费了
        this.notify();
    }

    public synchronized Chicken pop() throws InterruptedException {
        if (count==0){
            //等待生产者生产,消费者等待
            this.wait();
        }
        //如果可以消费
        count--;
        Chicken chicken = chickens[count];
        //吃完了,通知生产者生产
        this.notify();
        return chicken;
    }
}


信号灯法 ,标志位解决
public class TestPC2 {
    public static void main(String[] args) {
        TV tv = new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}
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();
            }
        }
    }
}
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){
                try {
                    this.tv.play("快乐大本营播放中");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else{
                try {
                    this.tv.play("红楼梦");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
class TV{
    // 演员表演 ,观众等待 T
    // 观众观看  , 演员等待  F
    String voice ;  //表演的节目
    boolean flag = true;
    public  synchronized void play(String voice) throws InterruptedException {
        if(!flag){
            this.wait();
        }
        System.out.println("演员表演了快乐大本营"+voice);
        this.voice = voice;
        this.flag = !this.flag;
        //通知观众观看
        this.notifyAll();  //通知唤醒
    }

    public synchronized void watch() throws InterruptedException {
        if (flag){
            this.wait();
        }
        System.out.println("观看了"+voice);
        //通知演员表演
        this.notifyAll();
        this.flag = !this.flag;
    }
}

线程池

public class TestPool {
    public static void main(String[] args) {
        // 1 创建服务
        // n   参数为线程池大小
        ExecutorService service = Executors.newFixedThreadPool(10);
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        
          service.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、付费专栏及课程。

余额充值