IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 英语渣渣学Java的day1 -> 正文阅读

[Java知识库]英语渣渣学Java的day1

Callable和Future创建线程(可以有返回值的线程)

(1)创建Callable接口的实现类,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
(2)创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
(3)使用FutureTask对象作为Thread对象的target创建并启动新线程。
(4)调用FutureTask对象的get()方法来获得子线程执行结束后的返回值

案例:
习题1:利用Callable和FutureTask完成 10! 8! 5!
类JieChengDemo

package com.gec.练习题;

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

class JieCheng implements Callable<Integer>{
	
	private int mun;



	public JieCheng(int mun) {
		super();
		this.mun = mun;
	}

	

	@Override
	public Integer call() throws Exception {
	if(mun == 0 && mun ==1) {
			int mun;
		}
		int mun1=1;
		for(int i = 1 ;i<=mun;i++) {
		    mun1*=i;
		}
		//累加和
		return mun1;
		
	}

	
}
public class JieChengDemo {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//创建线程对象
		JieCheng jie = new JieCheng(10);
		JieCheng jie2 = new JieCheng(8);
		JieCheng jie3 = new JieCheng(5);
		//2创建FutureTask 对象,封装了callable对象,返回值在这个对象FutureTask
		FutureTask<Integer> f = new FutureTask<Integer>(jie);
		FutureTask<Integer> f2 = new FutureTask<Integer>(jie2);
		FutureTask<Integer> f3 = new FutureTask<Integer>(jie3);
		//3借用Thread类来创建并启动线程
		Thread t = new Thread(f);
		Thread t2 = new Thread(f2);
		Thread t3 = new Thread(f3);
		//启动线程
		t.start();
		t2.start();
		t3.start();
		//4调用futuretask的get() 返回 integer
		Integer num = f.get();
		Integer num2 = f2.get();
		Integer num3 = f3.get();
		System.out.println("10阶乘为:"+num);
		System.out.println("8阶乘为:"+num2);
		System.out.println("5阶乘为:"+num3);

	}

}

运行结果:
注意:要创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。

线程池

思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完
放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交
通工具。

我们通过一张图来了解线程池的工作原理:
在这里插入图片描述好处:

  1. 提高响应速度(减少了创建新线程的时间)
  2. 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
  3. 便于线程管理
  4. corePoolSize:核心池的大小
  5. maximumPoolSize:最大线程数
  6. keepAliveTime:线程没有任务时最多保持多长时间后会终止

两个习题案例:
1.Callable和FutureTask完成 求 输入的3个数字,返回其中最大的一个!

package com.gec.练习题;

import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

class Max implements Callable<Integer>{
     private int a,b,c;
     //构造器
	public Max(int a, int b, int c) {
		super();
		this.a = a;
		this.b = b;
		this.c = c;
	}

	@Override
	public Integer call() throws Exception {
		//三目运算符进行比较
		int max = a>b ? a:b;
		int max2 = max>c ? max:c;
		return max2;
	}
	
}
public class MaxDemo {
   static Scanner sc = new Scanner(System.in);
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		System.out.println("请输入三个数,找出最大值:");
		int a = sc.nextInt();
		int b = sc.nextInt();
		int c = sc.nextInt();
		//创建Max对象
		Max m = new Max(a,b,c);
		//创建线程池
		ExecutorService service = Executors.newFixedThreadPool(2);
		//提交任务
		Future<Integer> f = service.submit(m);
		
		System.out.println("最大值为:"+f.get());

	}

}

运行结果:

  1. 用线程池完成 1+2+3+… +100 1+2+3+…+200
package com.gec.练习题;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

class LeiJia implements Callable<Integer>{
	private int num;

	public LeiJia(int num) {
		super();
		this.num = num;
	}

	@Override
	public Integer call() throws Exception {
		int n = 0;
		for(int i= 1;i <= num;i++) {
			n+=i;
		}
		return n;
	}
		
	
}
public class LeiJiaDemo {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//线程池
		ExecutorService lei = Executors.newFixedThreadPool(3);
		//创建LeiJia对象
		LeiJia j = new LeiJia(100);
		LeiJia j2 = new LeiJia(200);
		
		//提交任务
		Future<Integer> f = lei.submit(j);
		Future<Integer> f1 = lei.submit(j2);
		
		//调用get ,返回计算的结果
		Integer sum1 = f.get();
		Integer sum2 = f1.get();
		
		System.out.println("1+2+3+...+100的值:" + sum1);
		System.out.println("1+2+3+...+200的值:" + sum2);
		

	}

}

运行结果:
在这里插入图片描述

ForkJoinPool

ava7 提供了ForkJoinPool来支持将一个任务拆分成多个“小任务”并行计算,再把多个“小任务”的结果合并成总的计算结果。

ForkJoinPool是ExecutorService的实现类,因此是一种特殊的线程池。

使用方法:创建了ForkJoinPool实例之后,就可以调用ForkJoinPool的submit(ForkJoinTask task) 或invoke(ForkJoinTask task)方法来执行指定任务了。

下面的UML类图显示了ForkJoinPool、ForkJoinTask之间的关系:
在这里插入图片描述
案例:
无返回值实战——通过多线程分多个小任务进行打印数据

package com.gec.练习题;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.TimeUnit;

class PrintDemo extends RecursiveAction{
	
	//定义的常量 自定义 
	public static final int FIFTY = 50;
	//开始
	private int start;
	//结束 
	private int end;
	

	public PrintDemo(int start, int end) {
		this.start = start;
		this.end = end;
	}


	@Override
	protected void compute() {
		//判断
		if(end - start <= FIFTY) {
			for(int i = start;i <end;i++) {
				System.out.println(Thread.currentThread().getName() + "i的值:" + i);
			}
		}else {
			//进行找出middle
			int middle = (end + start)/2;
			//分解任务
			PrintDemo left = new PrintDemo(start,middle);
			PrintDemo right = new PrintDemo(middle, end);
			//任务
			left.fork();
			right.fork();
		}
	}
	
}

/*
 * 假设一堆打印任务 50个打印一台机器 ,如果超过50个打印,分若干个子打印任务
 */
public class ForkJoinPoolDemo2 {
	public static void main(String[] args) throws InterruptedException {
		//创建ForkJoinPool线程池
		ForkJoinPool fjp = new ForkJoinPool(32767);
		//提交任务
		fjp.submit(new PrintDemo(0, 300));
		
		//定时两秒完成任务
		fjp.awaitTermination(2, TimeUnit.SECONDS);
	}
}


运行结果:
在这里插入图片描述

ThreadLocal

ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

ThreadLoal 变量,线程局部变量,同一个 ThreadLocal 所包含的对象,在不同的 Thread 中有不同的副本。这里有几点需要注意:

因为每个 Thread 内有自己的实例副本,且该副本只能由当前 Thread 使用。这是也是 ThreadLocal 命名的由来。
既然每个 Thread 有自己的实例副本,且其它 Thread 不可访问,那就不存在多线程间共享的问题。
ThreadLocal 提供了线程本地的实例。它与普通变量的区别在于,每个使用该变量的线程都会初始化一个完全独立的实例副本。ThreadLocal 变量通常被private static修饰。当一个线程结束时,它所使用的所有 ThreadLocal 相对的实例副本都可被回收。

总的来说,ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用,也即变量在线程间隔离而在方法或类间共享的场景

下图可以增强理解:
在这里插入图片描述
案例:
ThreadLocal的简单使用

package com.gec.练习题;



public class ThreadLocalDemo {
	public static void main(String[] args) {
		
		//创建ThreadLocal对象
		ThreadLocal<String> local = new ThreadLocal<>();
		
		new Thread() {

			@Override
			public void run() {
				//设置值
				local.set("天生我材必有用");
				
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
				//在当前线程内访问 threadlocal的值
				String str = local.get();
				System.out.println("str:" + str);
				
				//只管调用
				//local.remove();
				//System.out.println("str:" + str);
				
			}
			
		}.start();
		
		
		try {
			Thread.sleep(1500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		System.out.println(Thread.currentThread().getName() + ",访问 local:" + local.get());//不行 main线程
	}
}

运行结果:
在这里插入图片描述
ThreadLocal类的用法非常简单,它只提供了如下3个public方法。
T get():返回此线程局部变量中当前线程副本中的值。
void remove():删除此线程局部变量中当前线程的值。
void set(T value):设置此线程局部变量中当前线程副本中的值。
网上经常说:这是一个线程安全的变量。这是错的!

经典例题:生产者/消费者问题

package com.gec.练习题;

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

/*
 * 1 消费者要消费,发出一个请求   通过一个导购员  会进行限制生产和促进生产这样一个角色 
 */
public class ProductCusmerDemo {
	public static void main(String[] args) {
		//集合
		List<String> list = new ArrayList<>();
		
		//获取时间
		long pro = System.currentTimeMillis();
		
		//生产者
		Thread t1 = new Thread() {

			@Override
			public void run() {
				//组装产品一个数字要进行累加
				int num = 0;
				
				//判断  System.currentTimeMillis():系统获得的时候 
				while(System.currentTimeMillis() - pro < 100) {
					synchronized (list) {
						//判断
						if(list.size() > 0) {
							//让工厂停止 生产
							try {
								list.wait();
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
						}else {
							//开足马力 生产
							list.add("荔枝"+ ++num);
							System.out.println(Thread.currentThread().getName() + "正在生产" + "荔枝" + num);
						}
					}
				}
			}
		};
		
		//生产者
		Thread t2 = new Thread() {

			@Override
			public void run() {
				//组装产品一个数字要进行累加
				int num = 0;
				
				//判断
				while(System.currentTimeMillis() - pro < 100) {
					synchronized (list) {
						//判断
						if(list.size() == 0) {
							//让工厂 生产
							list.notify();//唤醒生产线程
						}else {
							//消费
							list.remove("荔枝"+ ++num);
							System.out.println(Thread.currentThread().getName() + "正在吃" + "荔枝" + num);
						}
					}
				}
			}
		};
		
		//设置名字
		t1.setName("生产者");
		t1.start();
		
		t2.setName("消费者");
		t2.start();
	}
}

运行结果:
在这里插入图片描述

单列集合

Vector 有序,可重复,允许null,查询速度快,插入慢,底层用数组实现,扩容是当前容量的一倍,因为同步,比arraylist,linkedlist更慢了
双列集合:HashTable k-v 键值对,因为同步,key不重复,所以操作的效率低
线程安全案例:

package com.gec.线程安全的集合;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

public class XianChenAnQiangDemo {

	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		List<String> list2 = Collections.synchronizedList(list);
		
		//100个线程同时对同一个list作操作
		for (int i = 0; i < 100; i++) {
			new Thread() {
	
				@Override
				public void run() {
					//添加元素
					list2.add(UUID.randomUUID().toString().substring(0, 8));	
					
					//打印
					System.out.println(list2);
				}
				
				
			}.start();
		}
	}
}

运行结果:
在这里插入图片描述
线程不安全案例:

package com.gec.线程安全的集合;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.Vector;

public class XianChenBuAnQiangDemo {

	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		//List<String> list = new Vector<>();
		
		//100个线程同时对同一个list作操作
		for (int i = 0; i < 100; i++) {
			new Thread() {
	
				@Override
				public void run() {
					//添加元素
					list.add(UUID.randomUUID().toString().substring(0, 8));	
					
					//打印
					System.out.println(list);
				}
				
				
			}.start();
		}
	}
}

运行结果:
在这里插入图片描述
可以明显看到红色区域报错,代表了线程不安全。
我们一般情况可以查看对象的源代码有没有synchronized同步
比如:
在这里插入图片描述
注意:synchronizedListd对象源代码就有synchronized同步

单例

在一个应用,由始至终只有一个对象存在,这就是单例。
懒汉式:

package com.gec.单例;

import java.util.HashMap;
import java.util.Map;

class  LanHanShi{
	//私有的构造器
	private LanHanShi() {};
	
	//私有指向自己的静态实例
	private static LanHanShi lhs;//懒汉式单例 延迟加载(需要的时候再产生实例)
	//公共的访问实例的方法
	//双重检测  好处:需要的时候再产生单例
	public static LanHanShi getlnstance() {
		if(lhs == null) {
			synchronized (LanHanShi.class) {
				if(lhs == null) {
					lhs = new LanHanShi();
				}
			}
		}
		return lhs;
		
	}
}
class T extends Thread{
   static Map m = new HashMap();
	@Override
	public void run() {
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		for(int i = 0 ;i<100;i++) {
			LanHanShi lhs = LanHanShi.getlnstance();
			m.put(lhs, "a:"+i);
		}
		System.out.println(m);
	}
	
	
}
public class LanHanShiDemo {

	public static void main(String[] args) {
		for(int i = 0 ; i<110;i++) {
			T t = new T();
			t.start();
		}

	}

}

运行结果:
在这里插入图片描述
饿汉式:

package com.gec.单例;

import java.util.HashMap;
import java.util.Map;
class S2{
	private S2() {}
	private static S2 s2 = new S2();//饿汉式单例 
	
	//方法
	public static S2 getInstance() {
		return s2;
	}
}
class T2 extends Thread{
	static Map m = new HashMap();
	@Override
	public void run() {
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		for (int i = 0; i < 100; i++) {
			S2 s = S2.getInstance();
			m.put(s, "a:" + i);
		}
		
		System.out.println(m);
	}
}

public class EHanShi {
   
	public static void main(String[] args) {
		for(int i = 0;i<110;i++) {
			T t = new T();
			
			t.start();
		}
		

	}

}

运行结果:
在这里插入图片描述
饿汉式和懒汉式最明显的区别是饿汉式以上来就给自己产生实例

利用内部类产生的实例

package com.gec.单例;

import java.util.HashMap;
import java.util.Map;

class S3{
	private S3() {}
	
	private static class S3Holder{
		private static final S3 s3 = new S3();
	}
	
	//利用内部类产生的实例
	public static S3 getInstance() {
		return S3Holder.s3;
	}
}
class T3 extends Thread{
	static Map m = new HashMap();
	@Override
	public void run() {
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		for (int i = 0; i < 100; i++) {
			S3 s = S3.getInstance();
			m.put(s, "a:" + i);
		}
		
		System.out.println(m);
	}
}
public class NeBuLeiDemo {

	public static void main(String[] args) {
		for(int i = 0;i<110;i++) {
			T t = new T();
			
			t.start();
		}

	}

}

队列

队列的简单用法:

package com.gec.队列;



import java.util.concurrent.LinkedBlockingQueue;

/*
 * FIFO  First in First Out :先进先出  排队买东西
 */
public class DuiLieDemo {
	public static void main(String[] args) {
		//定义一个带3个容量的队列集合
		LinkedBlockingQueue lbk = new LinkedBlockingQueue(3);
		
		//判断
		System.out.println("empty:" + lbk.isEmpty());  //       true
		System.out.println("size:" + lbk.size());      //           0
		System.out.println("包含:" + lbk.contains("a"));//        false 
		System.out.println("容量:" + lbk.remainingCapacity());
		
		//添加数据  add  offer
		lbk.add(3);
		lbk.add(2);
		lbk.add("hello");
		
		//放第四个
		//lbk.add(33);
		boolean insertResult = lbk.offer(33);
		System.out.println(insertResult == true ?"插入成功":"插入失败");
		
		System.out.println("lbk移除前:" + lbk);
		//删除一个元素
		lbk.remove();
		System.out.println("lbk移除后:" + lbk);
		
		//查找不删除 获取头部第一个
		System.out.println("第一个值:" + lbk.peek());
		System.out.println("第一个值:" + lbk.peek());
		
		System.out.println("查找并删除第一个:" + lbk.poll());
		System.out.println("查找并删除:" + lbk.poll());
		
		System.out.println("尝试消费没有的元素:" + lbk.poll());
		
	}
}



运行结果:
在这里插入图片描述

方法的使用:
add 增加一个元素 如果队列已满,则抛出一个IllegalSlabEepeplian异常
remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
element 返回队列头部的元素 如果队列为空,则抛出一个 NoSuchElementException异常
offer 添加一个元素并返回true 如果队列已满,则返回false
poll 移除并返问队列头部的元素 如果队列为空,则返回null
peek 返回队列头部的元素 如果队列为空,则返回null
put 添加一个元素 如果队列满,则阻塞
take 移除并返回队列头部的元素 如果队列为空,则阻塞

第一次写这么多可能不够详细,可以下载我的笔记看看
https://download.csdn.net/download/weixin_45523942/20817715

参考
https://blog.csdn.net/u010445301/article/details/111322569

https://blog.csdn.net/chengqiuming/article/details/90736235

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-07 21:43:52  更:2021-08-07 21:43:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/10 18:29:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码