Java多线程详解

# Java多线程详解

1. 线程简介

  • 线程就是独立的执行路径
  • 程序运行时,及时没有自己创建线程,后台也会有多个线程
  • main()称之为主线程,为系统的入口,用于执行整个程序
  • 在一个进程中,如果开辟了多了线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关,先后顺序是不能人为干预的
  • 对同一份资源操作时,会存在资源抢夺的问题,需要键入并发控制
  • 线程会带来额外的开销,如cpu调度时间,并发控制开销
  • 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

2. 线程实现

2.1三种创建方式

image-20220110195820848

2.2 Thread

image-20220110201149852

线程是程序中执行的线程。 Java虚拟机允许应用程序同时执行多个执行线程

新建一个类 继承Thread 重写run()

package com.peng.demo01;

//练习Thread 实现多线程同步在下载图片

import org.apache.commons.io.FileUtils;

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

public class TestThread2 extends  Thread {

    private String url; //网络图片地址
    private String name;//保存的文件名

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

    //下载图片线程的执行体
    @Override
    public void run() {
        //super.run();
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url, name);
        System.out.println("下载了文件为:" + name);
    }

    public static void main(String[] args) {

        TestThread2 t1 = new TestThread2("https://t7.baidu.com/it/u=1819248061,230866778&fm=193&f=GIF", "1.jpg");
        TestThread2 t2 = new TestThread2("https://t7.baidu.com/it/u=4036010509,3445021118&fm=193&f=GIF", "2.jpg");
        TestThread2 t3 = new TestThread2("https://t7.baidu.com/it/u=91673060,7145840&fm=193&f=GIF", "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异常,downloader方法出现问题");
        }
    }
}

2.3实现Runnable

另一种方法来创建一个线程是声明实现类Runnable接口。 那个类然后实现了run方法。 然后可以分配类的实例,在创建Thread时作为参数传递,并启动

package com.peng.demo01;

public class TestThread4 implements Runnable {

    private String url; //网络图片地址
    private String name;//保存的文件名

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

    //下载图片线程的执行体
    @Override
    public void run() {
        //super.run();
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url, name);
        System.out.println("下载了文件为:" + name);
    }

    public static void main(String[] args) {

        TestThread2 t1 = new TestThread2("https://t7.baidu.com/it/u=1819248061,230866778&fm=193&f=GIF", "1.jpg");
        TestThread2 t2 = new TestThread2("https://t7.baidu.com/it/u=4036010509,3445021118&fm=193&f=GIF", "2.jpg");
        TestThread2 t3 = new TestThread2("https://t7.baidu.com/it/u=91673060,7145840&fm=193&f=GIF", "3.jpg");

        new Thread(t1).start();
        new Thread(t2).start();
        new Thread(t3).start();

    }
}

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

多个线程操作同一个资源的情况下,线程不安全,数据紊乱

package com.peng.demo01;

//多个线程操作同一个资源的情况下,线程不安全,数据紊乱
public class TestThread5 implements  Runnable {

    //票数
    private  int ticketNums = 10;
    @Override
    public void run() {
        while (true){
            if (ticketNums<=0){
                break;
            }
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName()+"---拿到了第"+ticketNums--+"票");
        }
    }

    public static void main(String[] args) {
        TestThread5 testThread5 = new TestThread5();

        new Thread(testThread5,"xm").start();
        new Thread(testThread5,"ls").start();
        new Thread(testThread5,"hn").start();
    }
}

2.5模拟龟兔赛跑

package com.peng.demo01;

import java.util.TreeMap;

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

            if (gameOver(i)) {
                break;
            }

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

    private boolean gameOver(int step) {

        //判断时候有胜利者
        if (winner != null) {
            return true;
        }
        {
            if (step >= 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.6实现Callable接口

  • 新建一个类实现Callable接口,需要返回值类型
  • 重写call方法,需要抛出异常
  • 创建目标对象
  • 创建执行服务
  • 提交执行
  • 获取结果
  • 关闭服务
package com.peng.demo02;


import org.apache.commons.io.FileUtils;

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

public class TestCallable implements Callable<Boolean> {

    private String url; //网络图片地址
    private String name;//保存的文件名

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

    @Override
    public Boolean call() {
        //super.run();
        WebDownloader webDownloader = new WebDownloader();
        webDownloader.downloader(url, name);
        System.out.println("下载了文件为:" + name);
        return true;
    }

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

        TestCallable t1 = new TestCallable("https://t7.baidu.com/it/u=1819248061,230866778&fm=193&f=GIF", "1.jpg");
        TestCallable t2 = new TestCallable("https://t7.baidu.com/it/u=4036010509,3445021118&fm=193&f=GIF", "2.jpg");
        TestCallable t3 = new TestCallable("https://t7.baidu.com/it/u=91673060,7145840&fm=193&f=GIF", "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 res1 = r1.get();
        boolean res2 = r2.get();
        boolean res3 = r3.get();

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

}

//下载器
 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方法出现问题");
        }
    }
}

2.7 静态代理模式

public class StaticProxy {

    public static void main(String[] args) {
        //You you = new You();
        //WeddingCompany weddingCompany = new WeddingCompany(you);
        //weddingCompany.HappyMarry();

        new Thread(()-> System.out.println("我爱你")).start();
        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();
        this.target.HappyMarry();
        after();
    }

    private void after() {
        System.out.println("结婚后");
    }

    private void before() {
        System.out.println("结婚前");
    }
}

3.Lamda表达式

  • 任何接口如果只包含唯一一个抽象方法,那么他就是函数式接口。
  • 对于函数式接口,我们可以通过lambda表达式来创建该接口
package com.peng.lambda;

/*

*/
public class TestLambda1 {

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

        @Override
        public void lambda() {
            System.out.println("I like myself2");
        }
    }

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

        ILike like2 = new Like2();
        like2.lambda();

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

            @Override
            public void lambda() {
                System.out.println("I like myself3");
            }
        }

        ILike like3 = new Like3();
        like3.lambda();

        //匿名内部类
        ILike like4 = new ILike() {

            @Override
            public void lambda() {
                System.out.println("I like myself4");
            }
        };
        like4.lambda();

        //lambda简化
        ILike like5 = ()->{
            System.out.println("I like myself5");
        };

    }

}

interface  ILike {
    void lambda();
}

class Like1 implements ILike{

    @Override
    public void lambda() {
        System.out.println("I like myself1");
    }
}

4.线程状态

image-20220110220510436

image-20220110220610306

4.1 停止线程

  • 不推荐JDK提供的stop(),destory()方法。(已废弃)
  • 推荐线程自己停止
  • 建议使用一个标志位进行终止变量,当flag=false,则终止线程运行。
  package com.peng.state;
  
  
  public class TestThreadStop 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) {
          TestThreadStop testThreadStop = new TestThreadStop();
          new Thre ad(testThreadStop).start();
  
          for (int i = 0; i < 1000; i++) {
              if (i == 900) {
                  testThreadStop.stop();
                  System.out.println("线程该停止了");
              }
          }
      }
  }

4.2 线程休眠

image-20220110222159453
package com.peng.state;

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

//模拟是10秒倒计时
public class TestThreadSleep {
    public static void main(String[] args) {
       /*
        try {
            tenDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        */
       //获取当前系统时间
        Date startTime = new Date(System.currentTimeMillis());

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

    }

    public static void tenDown() throws InterruptedException {
        int num = 10;
        while (true) {
            Thread.sleep(1000);
            System.out.println(num--);
            if (num <= 0) {
                break;
            }
        }
    }
}

4.3线程礼让

  • 礼让线程,让当前正在执行的线程暂停,但不阻塞
  • 将线程从运行状态转为就绪状态
  • 让cpu重新调度,礼让不一定成功
package com.peng.state;

public class TestThreadYield {
    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()+"线程结束执行");
    }
}

4.4 Join

  • Join合并线程,待此线程执行完成后,再执行其他线程,其他线程阻塞
  • 类似插队
package com.peng.state;

//测试join 想象为join
public class TestThreadJoin 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 {
        TestThreadJoin testThreadJoin = new TestThreadJoin();
        Thread thread = new Thread(testThreadJoin);

        for (int i = 0; i < 500; i++) {
            if (i == 200)
                thread.join();
            System.out.println("main" + i);

        }

    }
}

4.5 线程状态观测

Thread.State

  • NEW 尚未启动
  • RUNNABLE 执行
  • BLOCKED 阻塞
  • WAITING 等待
  • TIMED_WAITING 等待时间
  • TERMINATED 退出

image-20220110225204247

package com.peng.state;

public class TestThreadState {

    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 End");
        });

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

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

        while (state != Thread.State.TERMINATED) {
            Thread.sleep(100);
            state = thread.getState();
            //TIMED_WAITING
            //TERMINATED
            System.out.println(state);
        }
    }
}

4.6线程优先级

  • Java提供一个线程调度器来监控程序启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行。

  • 线程的优先级用数字表示,范围1~10

  • 使用getPriority() setPriority()获取或改变优先级

package com.peng.state;

//线程的优先级
public class TestThreadPriority extends  Thread {

    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(4);
        t3.start();

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

        /*

        t5.setPriority(-1);
        t5.start();

        t6.setPriority(11);
        t6.start();

         */
    }
}

class MyPriority implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "--->" + Thread.currentThread().getPriority());
    }

}

4.8守护线程

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

5.线程同步

5.1 线程安全

并发:同一个对象被多个线程同时操作

package com.peng.syn;

import com.sun.org.apache.bcel.internal.generic.ATHROW;

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

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

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

5.2同步方法

  • synchronized 方法和synchronized 快

    public synchronized void method(int args){}

  • synchronized控制对象的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行。

package com.peng.syn;

import com.sun.org.apache.bcel.internal.generic.ATHROW;

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

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

            }).start();
        }

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

5.4 JUC

package com.peng.syn;

import java.util.concurrent.CopyOnWriteArrayList;

public class TestJUC {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> 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());
    }
}

5.5死锁

定义:

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

如何避免死锁?

  • 互斥条件:一个资源每次只能被一个进程使用
  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
  • 不剥脱条件:进程已获得的资源,在未使用之前,不能强行剥夺。
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
package com.peng.lock;

//多个线程互相抱着对方需要的资源,然后形成僵持
public class DeadLock {
    public static void main(String[] args) {
        Makeup g1 = new Makeup(0, "灰");
        Makeup g2 = new Makeup(1, "白");

        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 girl) {
        this.choice = choice;
        this.girlName = girl;
    }

    @Override
    public void run() {
        //super.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+"获得镜子");
                }
                */

            }
            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+"获得口红");
                }
                 */
            }
            synchronized (lipstick) {
                System.out.println(this.girlName+"获得口红");
            }
        }
    }
}

5.6 Lock(锁)

5.6.1定义
  • JDK5.0,Java提供了更强大的线程同步机制-----通过显示定义同步锁对象来实现同步。(同步锁对象Lock)
  • java.utilconcurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应该先获得Lock对象
  • ReentrantLock(可重入锁)类实现了Lock,它拥有与synchronized相同的并发性和内存语音,在实现线程安全的控制中,比较常用的是ReetrantLock,可以显示加锁、释放锁。
package com.gaoji.lock;

import java.util.concurrent.locks.ReentrantLock;

//测试lock锁
public class TestLock {
    public static void main(String[] args) {
        TestLockImp testLockImp = new TestLockImp();
        new Thread(testLockImp).start();
        new Thread(testLockImp).start();
        new Thread(testLockImp).start();
    }
}

class TestLockImp implements  Runnable{
    int ticketNums = 10;

    //定义lock锁
    private  final 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();
            }
        }
    }
}
5.6.2 synchronized与lock的对比
  • Lock是显示锁(手动开启和关闭锁),synchronized是隐式锁,出了作用域自动释放
  • Lock只有代码块锁,synchronized有代码块锁和方法锁
  • 使用Lock锁,JVM话费较少的时间来调度线程,性能更好。并且具更好的扩展性(提供更多的子类)
  • 优先使用顺序lock>同步代码块(进入方法体,分配了相应资源)>同步方法(在方法体之外)

6.线程协作

6.1线程通信

生产者和消费者

生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件

image-20220111155004599

6.2 管程法

  • 生产者:负责生产数据的模块
  • 消费者:负责出来数据的模块
  • 缓冲如:消费者不能直接使用生产者的数据,他们之间有个"缓冲区"

生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据

image-20220111155326998

package com.gaoji.lock;

//测试生产者 消费者模型 --->利用缓冲区解决:管程法
//生产者 消费者 产品 缓冲去
public class TestPC {
    public static void main(String[] args) {
        SynContainer container = new SynContainer();

        new Productor(container).start();
        new Concumer(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++) {
            container.push(new Chicken(i));
            System.out.println("生产了"+i+"只鸡!!!");
        }
    }
}

//消费者
class Concumer extends  Thread{
    SynContainer container;
    public  Concumer(SynContainer container){
        this.container=container;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了--->" + container.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;
        count++;

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

    //消费者消费产品
    public synchronized Chicken pop() {
        //判断能否消费
        if (count == 0) {
            //等待生产者生产 消费者等待
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        count--;
        Chicken chicken = chickens[count];

        //消费完了 通知生产者生产
        this.notifyAll();
        return chicken;
    }
}

6.4 信号灯法

package com.gaoji.lock;

import javax.print.DocFlavor;

public class TestPC2 {
    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;
    }

}

7.线程池

提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用

  • 提高响应速度
  • 降低资源消耗
  • 便于线程管理

JDK5.0提供了线程池相关API:ExecutorService和Executors

  • void execute:执行任务 /命令,没有返回值,一般使用Runnable
  • Future submit(Callable task):执行任务,又返回值,一般用来执行Callable
  • void shutdown():关闭连接池

Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池

package com.gaoji.lock;

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

public class TestThreadPool {

    public static void main(String[] args) {
        //1.创建服务 创建线程池
        ExecutorService service = Executors.newFixedThreadPool(10);

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

        //2.关闭连接
        service.shutdown();
    }
}

class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
        /*
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + i);
        }
        */
    }
}

8.总结

package com.gaoji.lock;

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

//1.继承Thread类
class MyThread1 extends Thread{
    @Override
    public void run() {
        System.out.println("MyThread1");
    }
}

//2.实现Runnable
class MyThread2 implements Runnable{

    @Override
    public void run() {
        System.out.println("MyThread2");
    }
}

//3.实现Callble接口
class MyThread3 implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        System.out.println("MyThread3");
        return 100;
    }
}
posted @   peng_boke  阅读(316)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示