线程
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();
}
}
仓储模型
需求:
生产者线程不断的生产蛋糕,将蛋糕对象放入仓库中
消费者线程不断的消费蛋糕,将仓库中的蛋糕取出
要做到先生产的蛋糕先卖出(队列,先进先出,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();
}
}
线程池
知识点:线程池的概念
理解:线程池就是一个容器,存放多个线程,我们只需要将任务对象提交给线程池,线程池自动安排线程去处理即可
了解 - 线程完成一项任务的时间:
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();
}
}
创建指定线程个数的线程池
注意:多个线程之间的资源争抢
在创建指定线程个数的线程池中,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();
}
}
创建带缓存线程的线程池(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();
}
}
创建延迟任务的线程池
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();
}
}