Java多线程的使用

目录

什么是多线程?

继承Thread类

实现Runnable接口

龟兔赛跑

实现Callable接口

静态代理模式

Lambda表达式

线程状态

线程停止

线程休眠Sleep

线程礼让 yield

线程强制执行 join

观测线程状态

线程优先级

守护线程

线程同步机制

三大不安全案例

同步方法与同步块

死锁

Lock锁

生产者消费者问题

管程法

信号灯法

线程池

总结


什么是多线程?

        多线程(multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理或同时多线程处理器。在一个程序中,这些独立运行的程序片段叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”   。

继承Thread类

重写run()方法

使用时调用start()方法

public class TestThread1 extends Thread {

    @Override
    public void run() {
        //线程体
        for (int i = 0; i < 20; i++) {
            System.out.println("我在玩手机------>"+i);
        }
    }

    public static void main(String[] args) {

        //创建线程对象
        TestThread1 test=new TestThread1();

        test.start();

        for (int i = 0; i < 2000; i++) {
            System.out.println("我在吃饭-------*"+i);
        }
    }
}

实现Runnable接口

实现run()方法

将实现的对象放入Thread中调用start()方法

推荐使用实现Runnable接口的方式实现多线程

//多个线程同时操作同一个对象
//火车票
public class TestThread4 implements Runnable {

    private int a=10;

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

    public static void main(String[] args) {
        TestThread4 t=new TestThread4();

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

实现多线程下载网络图片

导入依赖

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>
//练习多线程,实现多线程同步下载图片
public class TestThread2 implements Runnable{

    private String url;
    private String name;

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

    public void run() {
        WebDownloader downloader=new WebDownloader();
        downloader.downloader(url,name);
        System.out.println("下载文件:"+name);
    }

    public static void main(String[] args) {
        //如果file不加路径会默认在当前项目中创建
        TestThread2 t1=new TestThread2("https://img1.baidu.com/it/u=407612955,34624712&fm=253&fmt=auto&app=120&f=JPEG","1.jpg");
        TestThread2 t2=new TestThread2("https://img1.baidu.com/it/u=407612955,34624712&fm=253&fmt=auto&app=120&f=JPEG","2.jpg");
        TestThread2 t3=new TestThread2("https://img1.baidu.com/it/u=407612955,34624712&fm=253&fmt=auto&app=120&f=JPEG","3.jpg");

        new Thread(t1).start();
        new Thread(t2).start();
        new Thread(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异常downloader方法出现问题");
        }
    }
}

注意:当多个线程操作同一个资源的时候会出现问题

龟兔赛跑

public class Race implements Runnable {
    private static String winner;

    public void run() {
        for (int i = 1; i <= 100; i++) {
            boolean flag = gemeOver(i);
            //模拟兔子睡觉
            if ("兔子".equals(Thread.currentThread().getName()) && i%50==0){
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //出现胜利者结束比赛
            if (flag){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
        }
    }

    public boolean gemeOver(int i){
        if (winner!=null){
            return true;
        }else if (i>=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接口
优点:有返回值,能抛出异常
 */
public class TestCallable implements Callable<Boolean> {
    private String url;
    private String name;

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

    public Boolean call() {
        WebDownloader downloader=new WebDownloader();
        downloader.downloader(url,name);
        System.out.println("下载文件:"+name);
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //如果file不加路径会默认在当前项目中创建
        TestCallable t1=new TestCallable("https://img1.baidu.com/it/u=407612955,34624712&fm=253&fmt=auto&app=120&f=JPEG","1.jpg");
        TestCallable t2=new TestCallable("https://img1.baidu.com/it/u=407612955,34624712&fm=253&fmt=auto&app=120&f=JPEG","2.jpg");
        TestCallable t3=new TestCallable("https://img1.baidu.com/it/u=407612955,34624712&fm=253&fmt=auto&app=120&f=JPEG","3.jpg");

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

        //提交执行
        Future<Boolean> r1=ser.submit(t1);
        Future<Boolean> r2=ser.submit(t2);
        Future<Boolean> r3=ser.submit(t3);

        //获取结果
        Boolean b1=r1.get();
        Boolean b2=r2.get();
        Boolean b3=r3.get();

        System.out.println(b1);
        System.out.println(b2);
        System.out.println(b3);

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

//下载器
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异常downloader方法出现问题");
        }
    }
}
  • 实现 Callable接口
  • 实现call()方法,该方法有返回值
  • 创建执行服务 ExecutorService ser= Executors.newFixedThreadPool(3);
  • 提交执行 Future r1=ser.submit(t1);
  • 获取结果 Boolean b1=r1.get();
  • 关闭服务 ser.shutdownNow();

其中Boolean是call()方法的返回值

静态代理模式

public class StaticProxy {

    public static void main(String[] args) {

        new MarryProxy(new You()).HappyMarry();

    }
}

interface Marry{
    public void HappyMarry();
}

class You implements Marry{

    public void HappyMarry() {
        System.out.println("今天结婚了很开心!");
    }
}

class MarryProxy implements Marry{
    private Marry marry;

    public MarryProxy(Marry marry){
        this.marry=marry;
    }

    public void HappyMarry() {
        on();
        marry.HappyMarry();
        to();
    }

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

    public void to(){
        System.out.println("结婚后,整理现场");
    }
}

静态代理总结

真实对象和代理对象都要实现同一接口

代理对象要代理真实角色

优点
    代理对象可以帮助真实角色做其他的事
    真实角色可以更加专注的做自己的事

Lambda表达式

函数式接口:只有一个方法接口的接口为函数式接口

lambda表达式的简化过程

public class TestLambda1 {

    //3.静态内部类
    static class Like2 implements ILike{

        public void lambda() {
            System.out.println("I like lambda2");
        }
    }

    public static void main(String[] args) {
        ILike like=new Like();
        like.lambda();

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

        //4.局部内部类
        class Like3 implements ILike{

            public void lambda() {
                System.out.println("I like lambda3");
            }
        }

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

        //5.匿名内部类
        like=new ILike() {
            public void lambda() {
                System.out.println("I like lambda4");
            }
        };
        like.lambda();

        //6.lambda表达式
        like=()->{
            System.out.println("I like lambda5");
        };

        like.lambda();

    }
}
//1.定义接口
interface ILike{
    void lambda();
}
//2.创建实现类
class Like implements ILike{

    public void lambda() {
        System.out.println("I like lambda");
    }
}
public class TestLambda2 {
public static void main(String[] args) {
        Love love=null;
        //匿名内部类
        love=new Love() {
            @Override
            public void love(int a) {
                System.out.println("I love you "+a);
            }
        };
        love.love(520);

        //lambda表达式
        love=(int a)->{
            System.out.println("I love you "+a);
        };
        love.love(521);

        //简化返回值类型
        love=(a)->{
            System.out.println("I love you "+a);
        };
        love.love(522);

        //简化小括号
        love=a->{
            System.out.println("I love you "+a);
        };
        love.love(523);

        //简化大括号
        love=a->System.out.println("I love you "+a);
        love.love(524);

    }
}
interface Love{
    void love(int a);
}

总结:

  • lambda表达式只有在一行代码的时候才能省略大括号,不然需要用大括号包括起来
  • lambda必须是函数式接口
  • 多个参数也可以去点参数类型,但是必须都去掉
  • 方法参数是一个的话不需要家小括号,超过一个则需要加

线程状态

线程停止

  • 建议线程自己停止--->利用次数,不建议死循环
  • 建议使用标志位停止线程-->设置一个标志位
  • 建议不要使用stop,destroy等过时或者JDK不建议使用的方法
public class TestStop implements Runnable {

    private boolean falg=true;

    public void run() {
        int i=0;
        while(falg){
            System.out.println("run...Threda:"+i++);
        }
    }

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

    public static void main(String[] args) {
        TestStop t=new TestStop();

        new Thread(t).start();

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

线程休眠Sleep

  1. sleep(时间)指定当前线程阻塞的毫秒数
  2. sleep存在异常
  3. sleep时间到达后,线程进入就绪状态
  4. sleep可以模拟网络延时,倒计时等
  5. 每一个对象都有一个锁,sleep不会释放锁

模拟网络延时:放大问题的发生性

import java.text.SimpleDateFormat;
import java.util.Date;

public class TestSleep2  {
    //模拟倒计时
    public static void tenDown() throws InterruptedException {
        int n=10;
        while (true){
            Thread.sleep(1000);
            System.out.println(n--);
            if (n<=0){
                break;
            }
        }
    }

    //打印当前系统时间
    public static void dataShow(){
        Date date=new Date();
        while (true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date));
                date=new Date();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        try {
            TestSleep2.tenDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        TestSleep2.dataShow();

    }
}

线程礼让 yield

  • 礼让线程,让当前正在执行的线程暂停,但不阻塞
  • 将线程从就运行态转为就绪状态
  • 让cpu调度礼让不一定会成功,kancpu心情
public class TestYield {

    public static void main(String[] args) {
        MyYield myYield=new MyYield();

        new Thread(myYield,"A").start();
        new Thread(myYield,"B").start();
    }
}

class MyYield implements Runnable{
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->线程开始");
        Thread.yield();//礼让
        System.out.println(Thread.currentThread().getName()+"-->线程结束");
    }
}

线程强制执行 join

此线程执行完后在执行其他线程

理解为插队

public class TestJoin implements Runnable {

    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("线程vip在执行:"+i);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TestJoin testJoin=new TestJoin();
        Thread t=new Thread(testJoin);
        t.start();

        for (int i = 0; i < 500; i++) {
            if (i==200){
                t.join();//线程插队,让cpu先执行他
            }
            System.out.println("main执行:"+i);
        }
    }
}

观测线程状态

public class TestState {
    public static void main(String[] args) {
        Thread thread=new Thread(()->{
            for (int i = 0; i < 5; i++) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("==========");
        });

        //观察状态
        Thread.State state = thread.getState();
        System.out.println(state);//new

        //观察启动后
        thread.start();//启动线程
        state = thread.getState();
        System.out.println(state);//run

        while (state!=Thread.State.TERMINATED){//只要线程不终止就一直输出
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            state=thread.getState();
            System.out.println(state);
        }
    }
}

线程优先级

  • 先设置优先级在使用
  • 执行顺序不一定是优先级高的先执行,但是概率会更大
class MyPriority implements Runnable{

    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);
        Thread t5=new Thread(myPriority);
        Thread t6=new Thread(myPriority);

        t1.start();

        t2.setPriority(1);//设置优先级
        t2.start();

        t3.setPriority(7);
        t3.start();

        t4.setPriority(Thread.MAX_PRIORITY);
        t4.start();

        t5.setPriority(Thread.MIN_PRIORITY);
        t5.start();

        t6.setPriority(3);
        t6.start();
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"-->"+Thread.currentThread().getPriority());//获取优先级
    }
}

守护线程

  • 线程分为用户线程和守护线程
  • 虚拟机必须确保用户线程执行完毕
  • 虚拟机不用等待守护线程执行完毕
  • 如,后台记录日志,监控内存,垃圾回收等待。

也就是说守护线程在用户线程结束后也会继续执行 ,直到程序结束虚拟机关闭才会结束。

public class TestDaemo {

    public static void main(String[] args) {
        God god=new God();
        You you=new You();

        Thread thread=new Thread(god);

        thread.setDaemon(true);//变成守护线程,该方法默认是false
        thread.start();

        //上帝插队的话就会无线循环
        /*try {
            thread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        new Thread(you).start();
    }
}

class God implements Runnable{

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

class You implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("你在开心的活着");
        }
        System.out.println("====goodbye,World!====");
    }
}

线程同步机制

由于一个进程多个线程访问同一块存储区域,带来方便的同时也带来了问题, 为了保证访问的正确性,因此引入了锁机制 synchronized,当一个线程获取 对象的排他锁后,其他线程必须等待,使用后释放锁即可,存在以下问题:

  • 一个线程持有锁,会导致其他需要此锁的线程挂起
  • 在多线竞争下,加锁,释放锁会导致上下文切换 和 调度延时,引起性能问题
  • 如果一个优先级高的线程等待一个优先级低的线程,会导致优先级倒置,
  • 引起性能问题

三大不安全案例

1.不安全的买票

public class UnsafeBankTicket {
    public static void main(String[] args) {
        Thank thank=new Thank();

        new Thread(thank,"小明").start();
        new Thread(thank,"老师").start();
        new Thread(thank,"黄牛党").start();
    }
}

class Thank implements Runnable{

    private int thank=10;
    private boolean falg=true;

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

    public void bny() throws InterruptedException {
        if (thank<=0){
            falg=false;
        }
        Thread.sleep(100);
        System.out.println(Thread.currentThread().getName()+"拿到了第"+thank--+"张票");
    }
}

2.不安全的取钱

public class UnsafeBank {
    public static void main(String[] args) {
        Account account=new Account(100,"银行账户");

        Drawing you=new Drawing(account,50,"你:");
        Drawing he=new Drawing(account,100,"他:");

        you.start();
        he.start();

    }

}

class Account{
    int money; //余额
    String name;

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

class Drawing extends Thread{

    Account account;//账户
    //取了多少钱
    int drawingMoney;
    //现在手里多少钱
    int newMoney;

    public Drawing(Account account,int drawingMoney,String name){
        super(name);
        this.account=account;
        this.drawingMoney=drawingMoney;
    }

    @Override
    public void run() {
        if (drawingMoney>account.money){
            System.out.println(this.getName()+"钱不够取得太多了");
            return;
        }

        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //账户余额
        account.money=account.money-drawingMoney;
        //手里的钱
        newMoney=newMoney+drawingMoney;

        System.out.println(this.getName()+"拿到了:"+newMoney);
        System.out.println(this.getName()+"手里有:"+drawingMoney);
        System.out.println(this.getName()+"账户余额为:"+account.money);
    }
}

3.线程不安全的集合

public class UnsafeList {
    public static void main(String[] args) {
        List list=new ArrayList();
        for(int i=0;i<10000;i++){
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }

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

同步方法与同步块

同步方法:在返回类型前加上synchronized

同步块:synchronized(obj){}

obj称为 同步监视器

  • obj可以是任何对象,但是推荐使用共享的资源对象作为同步监视器
  • 同步方法不用指定同步监视器,因为他的同步监视器就是this,就是这个对象本身, 或者是class

同步监视器的执行过程

  1. 第一个线程访问,锁定同步监视器,执行代码
  2. 第二个线程访问,发现同步监视器被锁定,无法访问
  3. 第一个线程执行完毕,解锁同步监视器
  4. 第二个线程访问,发现同步监视器没有锁,执行代码
public class UnsafeBank {
    public static void main(String[] args) {
        Account account=new Account(100,"银行账户");

        Drawing you=new Drawing(account,50,"你:");
        Drawing he=new Drawing(account,100,"他:");

        you.start();
        he.start();

    }

}

class Account{
    int money; //余额
    String name;

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

class Drawing extends Thread{

    Account account;//账户
    //取了多少钱
    int drawingMoney;
    //现在手里多少钱
    int newMoney;

    public Drawing(Account account,int drawingMoney,String name){
        super(name);
        this.account=account;
        this.drawingMoney=drawingMoney;
    }

    @Override
    public void run() {

        //锁定对象就是变化的量,增删改的对象
        synchronized(account){
            if (drawingMoney>account.money){
                System.out.println(this.getName()+"钱不够取得太多了");
                return;
            }

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //账户余额
            account.money=account.money-drawingMoney;
            //手里的钱
            newMoney=newMoney+drawingMoney;

            System.out.println(this.getName()+"拿到了:"+newMoney);
            System.out.println(this.getName()+"手里有:"+drawingMoney);
            System.out.println(this.getName()+"账户余额为:"+account.money);
        }
    }
}

CopyOnWriteArrayList

import java.util.concurrent.CopyOnWriteArrayList;

public class TestJUC {

    public static void main(String[] args) {
        CopyOnWriteArrayList list=new CopyOnWriteArrayList();
        for (int i = 0; i < 10000; i++) {
            new Thread(()->{
                list.add(Thread.currentThread().getName());
            }).start();
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list.size());
    }
}

死锁

死锁产生的四个必要条件

  1. 互斥条件:一个资源每次只能被一个进程调用
  2. 请求与保持条件:一个进程对请求资源阻塞时,对已获得的资源保持不放
  3. 不剥夺条件:进程以获得的资源,在没有使用完之前,不能被剥夺
  4. 循环等待条件:若干资源之间形成一种头尾相接循环等待资源的关系
public class DeadLock {

    public static void main(String[] args) {
        Makup g1=new Makup(0,"小红");
        Makup g2=new Makup(1,"小美");

        g1.start();
        g2.start();
    }
}

//口红
class Lipstick{
}

//镜子
class Mirror{
}

class Makup extends Thread{

    static Lipstick lipstick=new Lipstick();
    static Mirror mirror=new Mirror();

    int n;//标记
    String girName;//女孩的名字

    public Makup(int n,String girName){
        this.n=n;
        this.girName=girName;
    }

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

    private void makup() throws InterruptedException {
        if (n==0){
            synchronized(lipstick){
                System.out.println(this.girName+"拿到了口红");
                Thread.sleep(1000);

            }
            synchronized (mirror){
                System.out.println(this.girName+"拿到了镜子");
            }
        }else{
            synchronized(mirror){
                System.out.println(this.girName+"拿到了镜子");
                Thread.sleep(2000);

            }
            synchronized (lipstick){
                System.out.println(this.girName+"拿到了口红");
            }
        }
    }
}

Lock锁

  • Lock锁是显示锁(手动开启和关闭锁)sunchronized是隐式锁,出了作用域自动释放
  • Lock只有代码块锁
  • 使用Lock锁,JVM将花费较少的时间调度线程,性能更好,并且具有更好的扩展性
  • 优先使用顺序:Lock > 同步代码块(已经进入了方法体,分配了相应资源) >同步方法(在方法体之外)
import java.util.concurrent.locks.ReentrantLock;

//测试Lock锁
public class TestLock {

    public static void main(String[] args) {
        TestLock2 t1=new TestLock2();

        new Thread(t1).start();
        new Thread(t1).start();
        new Thread(t1).start();
    }
}
class TestLock2 implements Runnable{

    int n=10;
    private final ReentrantLock lock=new ReentrantLock();

    public void run() {
        while (true){
            lock.lock();
            if (n>0){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock.unlock();
                }
                System.out.println(n--);
            }else{
                break;
            }
        }
    }
}

生产者消费者问题

  • wait():表示线程会一直等待,直到其他线程通知,与sleep不同,会释放锁
  • wait(long timeout):指定等待的毫秒数
  • notify():唤醒一个处于等待状态的线程
  • notifyAll():唤醒同一个对象上所有调用wait()方法的线程,优先级高的线程 优先调度

注意:均是Object中的方法,都只能在同步方法或同步代买块中使用,否则会抛出异常

管程法

//测试:生产者消费者模型-->利用缓冲区解决:管程法
//生产者,消费者,缓冲区,产品
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 = 1; i <=100; i++) {
            synContainer.push(new Chickn(i));
            System.out.println("生产者生产了"+i+"只鸡");
        }
    }
}

//消费者
class Consumer extends Thread{
    SynContainer synContainer;

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

    @Override
    public void run() {
        for (int i = 1; i <=100; i++) {
            System.out.println("消费者消费了"+synContainer.pop().id+"只鸡");
        }
    }
}

//产品
class Chickn{
    public int id;

    public Chickn(int id) {
        this.id = id;
    }
}

//缓冲区
class SynContainer{

    //需要一个容器大小
    Chickn[] chickns=new Chickn[10];
    //计数器
    int count=0;

    //生产者放入产品
    public synchronized void push(Chickn chickn){
        //如果生产满了就要等待消费者消费
        if (count==chickns.length){
            //通知消费者消费,生产者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果没有满,我们就丢入产品
        chickns[count]=chickn;
        count++;

        //通知消费者消费
        this.notifyAll();
    }

    //消费者消费产品
    public synchronized Chickn pop(){
        //如果没有产品了通知生产者生产
        if (count==0){
            //消费者停止消费,通知生产者生产
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果可以消费
        count--;
        Chickn chickn = chickns[count];
        //吃完了,通知生产者生产
        this.notifyAll();

        return chickn;
    }
}

信号灯法

//测试:生产者消费者问题-->信号灯法
public class TestPc2 {
    public static void main(String[] args) {
        TV tv=new TV();

        Player player=new Player(tv);
        Watcher watcher=new Watcher(tv);

        player.start();
        watcher.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){
                tv.play("快乐大本营:"+i);
            }else{
                tv.play("乡村爱情:"+i);
            }
        }
    }
}
//消费者-->观众
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 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.name=name;
        this.notifyAll();
        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;
    }
}

线程池

  • JDK 5.0 起提供了线程池相关API:ExecutorService和Executors
  • ExecutorService:真正的线程池接口。常见子类ThreadPollExecutor
    • void execute(Runnable command):执行任务命令,没有返回值,一般用来执行Runnable
    • Future sumbit(Callable task):执行任务,有返回值,一般执行Callable
    • void shutdown():关闭连接池
  • Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

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

        service.execute(new MyThread());//执行命令
        service.execute(new MyThread());
        service.execute(new MyThread());

        //关闭连接池
        service.shutdownNow();
    }
}

class MyThread implements Runnable{

    @Override
    public void run() {
            System.out.println(Thread.currentThread().getName());
    }
}

总结

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadNew {
    public static void main(String[] args) {
        new Mythread1().start();
        new Thread(new Mythread2()).start();
        FutureTask<Integer> futureTask=new FutureTask<Integer>(new Mythread3());
        new Thread(futureTask).start();
        try {
            Integer integer=futureTask.get();
            System.out.println(integer);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

class Mythread1 extends Thread{

    @Override
    public void run() {
        System.out.println("Mythread1");
    }
}
class Mythread2 implements Runnable{

    @Override
    public void run() {
        System.out.println("Mythread2");
    }
}
class Mythread3 implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        System.out.println("Mythread3");
        return 100;
    }
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值