线程

1. 线程局部变量共享

创建A类

package com.wz.thread11;

import java.util.concurrent.ConcurrentHashMap;

public class A {

    public void println(){

        ConcurrentHashMap<Thread,Data> map = DataCenter.getMap();
        Thread thread = Thread.currentThread();

        Data value = map.get(thread);

        System.out.println(thread.getName() + "中的A类对象共享的数据为:" + value);
    }
}

创建B类

package com.wz.thread11;

import java.util.concurrent.ConcurrentHashMap;


public class B {

    public void println(){

        ConcurrentHashMap<Thread,Data> map = DataCenter.getMap();
        Thread thread = Thread.currentThread();

        Data value = map.get(thread);

        System.out.println(thread.getName() + "中的B类对象共享的数据为:" + value);
    }
}

创建Data类,存放数据

package com.wz.thread11;

//容器类
public class Data {

    private String str;
    private int i;

    public Data() {
    }

    public Data(String str, int i) {
        this.str = str;
        this.i = i;
    }

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }

    @Override
    public String toString() {
        return "Data [str=" + str + ", i=" + i + "]";
    }
}

创建DataCenter,利用ConcurrentHashMap存储线程中的局部变量

package com.wz.thread11;

import java.util.concurrent.ConcurrentHashMap;

//数据中心
public class DataCenter {

    private static ConcurrentHashMap<Thread, Data> map;

    static{
        map = new ConcurrentHashMap<>();
    }

    public static ConcurrentHashMap<Thread, Data> getMap() {
        return map;
    }
}

测试类test01

package com.wz.thread11;

import java.util.concurrent.ConcurrentHashMap;

public class test01 {
    /**
     * 知识点:线程的局部变量共享
     * 理解:线程中有一个资源,该资源只能共享给该线程下的任意对象
     *
     * 需求:共享多个数据
     */
    public static void main(String[] args) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                Data data = new Data("张三", 20);

                ConcurrentHashMap<Thread,Data> map = DataCenter.getMap();
                map.put(Thread.currentThread(), data);

                A a = new A();
                B b = new B();
                a.println();
                b.println();
            }
        }, "线程1").start();

        new Thread(new Runnable() {
            @Override
            public void run() {

                Data data = new Data("李四", 21);

                ConcurrentHashMap<Thread,Data> map = DataCenter.getMap();
                map.put(Thread.currentThread(), data);

                A a = new A();
                B b = new B();
                a.println();
                b.println();
            }
        }, "线程2").start();
    }
}

2023年7月6日,线程局部变量共享,仓储模型,线程池_线程局部变量的共享

仓储模型

需求:

生产者线程不断的生产蛋糕,将蛋糕对象放入仓库中

消费者线程不断的消费蛋糕,将仓库中的蛋糕取出

要做到先生产的蛋糕先卖出(队列,先进先出,LinkedList)

synchronized 修饰方法和this修饰对象应指向同一个对象

public synchronized void push(Cake cake){
        while (curCapacity>=maxCapacity){
            try {
                this.wait();//等待:1.将当前线程记录到对象监视器中 2.释放锁资源 3.让线程进入到堵塞状态
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

创建Cake类:属性包括(品牌,价格,生产日期)

package Storage_model_01;

//蛋糕类
public class Cake {

    private String brand;
    private double price;
    private String datatime;

    public Cake() {
    }

    public Cake(String brand, double price, String datatime) {
        this.brand = brand;
        this.price = price;
        this.datatime = datatime;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public String getDatatime() {
        return datatime;
    }

    public void setDatatime(String datatime) {
        this.datatime = datatime;
    }

    @Override
    public String toString() {
        return brand + " -- " + price + " -- " + datatime;
    }
}

创建Store类,属性包括(存放蛋糕对象的容器、当前容量、最大容量),方法包括(入库、出库)

package Storage_model_01;

import java.util.LinkedList;

//仓库类
public class Store {

    private static final int DEFAUL_INIT_CAPACITY = 20;
    private LinkedList<Cake> list;
    private int maxCapacity;
    private int curCapacity;

    public Store() {
        this(DEFAUL_INIT_CAPACITY);
    }

    public Store(int maxCapacity) {
        list = new LinkedList<>();
        this.maxCapacity = maxCapacity;
    }

    //入库
    public synchronized void push(Cake cake){
        while (curCapacity>=maxCapacity){
            try {
                this.wait();//等待:1.将当前线程记录到对象监视器中 2.释放锁资源 3.让线程进入到堵塞状态
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        list.add(cake);
        curCapacity++;
        System.out.println("入库,当前容量为:" + curCapacity);
        this.notifyAll();
    }

    //出库
    public synchronized Cake pop(){
        while (curCapacity<=0){
            try {
                this.wait();//等待:1.将当前线程记录到对象监视器中 2.释放锁资源 3.让线程进入到堵塞状态
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Cake cake = list.removeFirst();
        curCapacity--;
        System.out.println("出库,当前容量为:" + curCapacity + " -- " + cake);
        this.notifyAll();
        return cake;
    }
}

生产者线程类Producer

package Storage_model_01;

import java.time.LocalDateTime;

public class Producer extends Thread{
    private Store store;
    public Producer(Store store) {
        this.store=store;
    }

    @Override
    public void run() {
        while (true){
            Cake cake = new Cake("罗莎", 6, LocalDateTime.now().toString());
            store.push(cake);
        }
    }
}

消费者线程类Consumer

package Storage_model_01;

public class Consumer extends Thread{
    private Store store;

    public Consumer(Store store) {
        this.store = store;
    }

    @Override
    public void run() {
        while(true){
            store.pop();
        }
    }
}

测试类test01

package Storage_model_01;

public class test01 {
    public static void main(String[] args) {
        Store store = new Store();
        Producer p1 = new Producer(store);
        Producer p2 = new Producer(store);
        Consumer c1 = new Consumer(store);
        Consumer c2 = new Consumer(store);

        p1.start();
        p2.start();
        c1.start();
        c2.start();
    }
}

2023年7月6日,线程局部变量共享,仓储模型,线程池_线程局部变量的共享_02

线程池

知识点:线程池的概念

理解:线程池就是一个容器,存放多个线程,我们只需要将任务对象提交给线程池,线程池自动安排线程去处理即可

了解 - 线程完成一项任务的时间:

1.创建线程 - time1

2.使用线程 - time2

3.销毁线程 - time3

为什么使用线程池:

1.线程池的技术调整并优化time1和time3的时间,可以将创建线程池放在项目启动时,销毁线程池放在项目销毁时

2.有效的控制项目中线程的个数

3.提高了线程的复用率

1. Java自带线程池

创建任务类Task implements Runnable

package Pool01;

public class Task implements Runnable{
    private int num;//定义任务数量

    public Task(int num) {
        this.num = num;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " -- 任务" + num + "被执行了");
    }
}

创建单个线程的线程池

注意:线程池的关闭 pool.shutdown();

package Pool01;

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

public class test01 {
    public static void main(String[] args) {
        //创建单个线程的线程池
        ExecutorService pool = Executors.newSingleThreadExecutor();
        for (int i = 1; i <=100 ; i++) {
            Task task = new Task(i);
            //将任务对象提交给线程池
            pool.submit(task);
        }
        //关闭线程池
        pool.shutdown();
    }
}

2023年7月6日,线程局部变量共享,仓储模型,线程池_线程池_03

创建指定线程个数的线程池

注意:多个线程之间的资源争抢

在创建指定线程个数的线程池中,Task的执行顺序是不确定的。这是因为线程池中的线程是并发执行的,它们的执行顺序是由线程调度器决定的,而不是按照任务提交的顺序执行。

当任务被提交给线程池后,线程池会根据可用的线程资源选择一个空闲的线程来执行任务。如果所有线程都在执行其他任务,那么任务会等待直到有线程可用。一旦线程可用,它会被分配给一个任务并开始执行。

在你提供的代码中,线程池使用了固定大小为3的线程池。因此,同时最多只能有3个任务被执行,并且在大部分情况下,线程池中的线程会按照任务的提交顺序来执行。但是,由于线程的调度是由操作系统和线程调度器控制的,因此无法保证线程执行的顺序与任务的提交顺序完全一致。

所以,你观察到的任务执行顺序可能是由于线程调度的原因,导致部分任务的执行顺序发生了变化。这是正常的,并不代表程序有问题。如果你需要确保任务按照特定的顺序执行,可以考虑使用其他机制,如等待/通知机制或者使用线程间的同步机制来控制任务的执行顺序。

package Pool01;

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

public class test02 {
    public static void main(String[] args) {
        //创建指定线程个数的线程池
        ExecutorService pool = Executors.newFixedThreadPool(3);

        for (int i = 1; i <=100 ; i++) {
            Task task = new Task(i);
            //将任务对象提交给线程池
            pool.submit(task);
        }
        //关闭线程池
        pool.shutdown();

    }
}

2023年7月6日,线程局部变量共享,仓储模型,线程池_线程池_04

创建带缓存线程的线程池(60S没有工作的线程认为是闲置线程,会被回收掉)

注意:刚开始没有线程,当任务类传入后,系统会自动计算分配线程数量

package Pool01;

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

public class test03 {
    public static void main(String[] args) {
        //创建带缓存线程的线程池(60S没有工作的线程认为是闲置线程,会被回收掉)
        ExecutorService pool = Executors.newCachedThreadPool();
        for (int i = 1; i <=100 ; i++) {
            Task task = new Task(i);
            //将任务对象提交给线程池
            pool.submit(task);
        }
        //关闭线程池
        pool.shutdown();
    }
}

2023年7月6日,线程局部变量共享,仓储模型,线程池_线程池_05

创建延迟任务的线程池

pool.schedule(new Task(1),5, TimeUnit.SECONDS);

package Pool01;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class test04 {
    public static void main(String[] args) throws InterruptedException {
        //创建延迟任务的线程池
        ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor();
        //提交延迟任务 - 5s后提交该任务
        pool.schedule(new Task(1),5, TimeUnit.SECONDS);
        //关闭线程池
        pool.shutdown();
    }
}

2023年7月6日,线程局部变量共享,仓储模型,线程池_线程池_06