史上最全讲解:JAVA中的Map与Thread

史上最全讲解:JAVA中的Map与Thread

Map

  • Map :存储的每一个数据都是一个键值对形式存在的 k,v
  • key 无序的**,唯一的** -->就是一个set集合
  • value 无序的,可重复的
  • 一个key对象一个value,两者之间存在映射关系
  • 如果存储数据的时候,key相同,value的值会覆盖
  • map中,HashMap的去重,根据Map的key进行计算
  • TreeMap的去重+排序,根据Map的key进行计算
  • Map中的去重都是根据key来进行计算的
  • 如果一个key,想要对象多个value值,可以把多个value存在一个容器中,而容器对象是一个
  • 如果使用HashMap存储数据,key是自定义的引用数据类型 Student对象,value存储学生的身高
  • 要求:实现去重,如果key相同,value不许覆盖
    Map的实现类接口有两个 HashMap和TreeMap

HashMap

  • HashMap 的key值如果是自定义引用数据类型,如果要达达到去重的目的,需要重写hashcode 和 equals方法,如果要想相同的key情况下的value值不被覆盖,那么需要在获取值(put)之前进行判断当前的key是否存在(containsKey)
package com.shsxt.map02;
import java.util.HashMap;
public class HashMapDemo03 {
	static HashMap<Student,Double> map=new HashMap();
	public static void main(String[] args) {
		/*map.put(new Student("1001","于泳洋",18), 180.00);
		map.put(new Student("1001","于泳洋",18), 190.00);*/
		putValue(new Student("1001","于泳洋",18), 180.0);
		putValue(new Student("1001","于泳洋",18), 190.0);
		System.out.println(map);
	}
	
	public static void putValue(Student s ,Double d){
		if(!map.containsKey(s)){
			map.put(s, d);
		}else{
			System.out.println("已经存在指定的key");
		}
	}
}

class Student implements Comparable<Student>{//根据键值student来进行去重
//内部比较器用Comparable
	private String id;
	private String name;
	private int height;
	public Student() {
		// TODO Auto-generated constructor stub
	}
	public Student(String id, String name, int height) {
		super();
		this.id = id;
		this.name = name;
		this.height = height;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", height=" + height + "]";
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + height;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (height != other.height)
			return false;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
		@Override
	public int compareTo(Student o) {//对身高进行排序
		// TODO Auto-generated method stub
		//if()
		return Double.compare(o.height,this.height );
	}
}

TreeMap

  • TreeMap 去存储自定义的引用数据类型的数据key是自定义的引用数据类型 Student对象,根据学生的身高进行排序
  • TreeaMap的特点是:其中数据会自动升序排序,根据学生的身高进行排序
  • 实现的步骤:
  •  1.去重  实现内部|外部比较器 比较的原则根据key,不能根据value
    
  •  2.根据需求排序
    
  •  	key的内容决定排序和去重的原则,这是TreeMap默认的比较过程
    
package com.shsxt.map02;
import java.util.TreeMap;
public class TreeMapDemo04 {
	static TreeMap<Student,String> tree=new TreeMap((s1,s2)->   ((Student)s2).getHeight() -((Student)s1).getHeight());
	public static void main(String[] args) {
		tree.put(new Student("100","张三",180), "java");
		tree.put(new Student("101","李四",170), "大数据");
		tree.put(new Student("100","张三",180), "python");
		System.out.println(tree);
	}
}
package com.shsxt.map02;
//Student类
public class Student implements Comparable<Student>{
	private String name;
	private double height;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getHeight() {
		return height;
	}
	public void setHeight(double height) {
		this.height = height;
	}
	public Student(String name, double height) {
		super();
		this.name = name;
		this.height = height;
	}
	public Student() {
		super();
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", height=" + height + "]";
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		long temp;
		temp = Double.doubleToLongBits(height);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (Double.doubleToLongBits(height) != Double.doubleToLongBits(other.height))
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	@Override
	public int compareTo(Student o) {//对身高进行排序
		// TODO Auto-generated method stub
		//if()
		return Double.compare(o.height,this.height );
	}
}

Hash(HashSet/HashMap)与Tree(TreeSet/TreeMap)比较:
都是不可重复的 无序的
在去重的时候自定义数据类型都需要重写hashcode和equals方法
Tree在排序的时候,自定义类型需要实现Compatator接口(compare方法外部比较器)或者继承Comporatable(compareTo)内部比较器

Properties

Properities是Hashtable的子类的子类,要求键与值只能为字符串 ,不能为 null ,常与 配置文件与外界交互 的信息 ) 即内存与存储介质 文件、数据库、网络、服务器内存等 交互。

  • Properties Properties 可保存在流中或从流中加载。 key与value都是字符串类型的数据
  • 配置文件使用:
  • 1.项目右键->source floder->file->添加键值对类型的数据
  • 2.通过Properties 的load方法,从资源文件中获取资源流,读入数据
package com.shsxt.properties;

import java.io.IOException;
import java.util.Properties;

public class Properties01 {
	public static void main(String[] args) throws IOException {
		Properties pro = new Properties();
		pro.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
		System.out.println(pro.getProperty("name"));
	}
}

HashMap\HashTable\Properties三者的比较:
HashMap: 线程不安全,效率高 . 允许 key 或 value 为 null
HashTable: 线程安全,效率低 . 不允许 key 或 value 为 null
Properties: Hashtable 的子类, key 和 value 都是 string

Thread

多线程:
多任务同时执行,多条路径执行,如果没有多任务,不需要使用多线程
线程和进程之间的区别:
  1.进程包含1~n个线程
   2.每个进程有自己的代码和运行空间
  3.一系列线程共享继承的资源
  4.进程是资源分配的最小单位,线程是cpu调度的最小单位
  5.线程之间切换开销小,进程之间开销大.

多线程的开启方式****
  1.继承Thread类,重写run()方法,在方法中定义多线程的线程体
  2.实现Runnable接口,重写run()方法,在方法中定义多线程的线程体 —推荐
  3.实现Callable接口,重写call()方法,在方法中定义多线程的线程体
   多线程的状态问题
  多线程的线程安全问题 ****
   线程通信问题

开启多线程方法1

继承Thread类,重写run()方法,在方法中定义多线程的线程体

public class ThreadDemo01 extends Thread {
	/*
	 * 定义线程体
	 */
	@Override
	public void run() {
		for(int i=0;i<=20;i++){
			System.out.println("一遍敲代码...");
		}
	}

	public static void main(String[] args) {
		//线程创建
		ThreadDemo01 th=new ThreadDemo01();
		//th.run();  //方法的调用
		th.start(); //线程的开启
		for(int i=0;i<=20;i++){
			System.out.println("一遍聊微信...");
		}
	}
}

多线程开启方法2

  • 实现Runnable接口,重写run()方法
    1.接口可以多实现,类只能单继承
    2.实现资源共享
package com.shsxt.thread05;
public class ThreadDemo02 implements Runnable{
	public static void main(String[] args) {
		ThreadDemo02 th = new ThreadDemo02();
		Thread t = new Thread(th);//使用静态代理 将th对象座位参数传进来
		//使用Thread的start方法 降低耦合
		t.start();
		for(int i=0;i<50;i++){
			System.out.println("123");
		}
	}
	@Override
	public void run() {
		for(int i=0;i<50;i++){
			System.out.println("456");
		}
	}
}

多线程开启方法3

实现callable接口,重写call()方法
特点:异常可以捕获(runnable接口run方法异常只能抛出),效率高

12306买票问题

package com.shsxt.thread05;
/*
 * 100张票,3个人买完  
 * 共享的资源:100张票
 * 
 */
public class Web12306_03 implements Runnable{
	int tickets=100;
	/*
	 * 买票
	 */
	@Override
	public void run() {
		while(true){
			//A B C
			if(tickets<=0){
				break;
			}
			try {
				Thread.sleep(100); //ms数
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()+"正在购买第"+tickets--);
		}
	}
	public static void main(String[] args) {
		Web12306_03 web=new Web12306_03();
		Thread t1=new Thread(web,"凌希");//Thread的重载方法
		Thread t2=new Thread(web,"张苏蒙");
		Thread t3=new Thread(web,"刘易舟");
		t1.start();
		t2.start();
		t3.start();
	}
}

龟兔赛跑

龟兔赛跑: 谁先跑完100步就赢了,但是兔子每跑十步休息2ms,只要有人赢了,游戏就结束

package com.shsxt.thread05;
/*
 * 比赛类:
 */
public class Racer04 implements Runnable{
	String winner = null; //存储胜利者的名字
	@Override
	public void run() {
		for(int i=1;i<=100;i++){
			if("兔子".equals(Thread.currentThread().getName()) && i%10==0){
				try {
					Thread.sleep(20);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				if(checkOver(i)){
					break;
				}
			}
			
			System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
			if(checkOver(i)){
				break;
			}
		}
	}
	/*
	 * 如果返回true,代表游戏结束
	 * 如果返回false,证明游戏继续
	 */
	public boolean checkOver(int i){
		if(winner==null){
			if(i==100){
				winner= Thread.currentThread().getName();
			}else{
				return false;
			}
		}
		return true;
	}
	public static void main(String[] args) {
		Racer04 race=new Racer04();
		Thread th1=new Thread(race,"兔子");
		Thread th2=new Thread(race,"乌龟");
		th1.start();
		th2.start();
	}
}

线程状态

  • 新生状态new :new的时候,线程处于新生状态

  • 就绪状态runnable:start()方法后线程进入到就绪状态,等待cpu的调度,进入到就绪队列

  • 运行状态running:cpu把时间片资源分配给某一个线程,线程才可以进入到运行状态

  • 阻塞状态block:sleep()非能够正常运行完毕,直到阻塞解除

  • 终止状态dead:线程结束

  • 一个线程如何进入就绪状态:
    1.start()
    2.yield() 礼让线程
    yield() 礼让线程,高风亮节

package com.shsxt.threadstate;
public class ThreadYield02 implements Runnable{
   public static void main(String[] args) {
   	new Thread(new ThreadYield02(),"A").start();
   	new Thread(new ThreadYield02(),"B").start();
   }
   @Override
   public void run() {
   	System.out.println(Thread.currentThread().getName()+"开启了");
   	Thread.yield();//礼让出来之后 CPU再次分配
   	System.out.println(Thread.currentThread().getName()+"结束了");
   }
}

3.阻塞解除
4.线程切换,被切换的线程直接进入就绪状态
一个线程如何进入阻塞状态:
1.sleep()
sleep(): 抱着资源睡觉
对象锁不会释放,但是会让出cpu的资源
放大问题的可能性
模拟网络延迟
2.wait() 线程等待
3.join() 插队线程(儿子买烟例子)
爸爸让儿子买烟,先发出买烟的指令,儿子接收到以后再去买烟,然后爸爸抽烟,并不是爸爸一说让儿子买烟自己就能抽到,此时需要开启儿子买烟这个线程,买到烟之后(即买烟线程结束)爸爸再抽烟(即执行抽烟的代码)

package com.shsxt.threadstate;
public class ThreadJoin01 {
   public static void main(String[] args) {
   	new Thread(new Father()).start();//自己没有start方法 借用Thread的
   }
}
class Father implements Runnable {
   @Override
   public void run() {
   	System.out.println("买烟");
   	Thread th = new Thread(new Son());
   	th.start();
   	try {
   		th.join();
   	} catch (InterruptedException e) {
   		// TODO Auto-generated catch block
   		e.printStackTrace();
   	}
   	System.out.println("抽烟");
   }
}
class Son implements Runnable {

   @Override
   public void run() {
   	System.out.println("去买烟");
   	for(int i=0;i<10;i++){
   		try {
   			Thread.sleep(1000);
   		} catch (InterruptedException e) {
   			// TODO Auto-generated catch block
   			e.printStackTrace();
   		}
   		System.out.println(i+"秒过去了");
   	}
   }
}

Thread.State getState() 返回该线程的状态。
线程的优先级: 1~10,1最小 10最大,默认5
提高优先执行可能性,但是不是一定的
void setPriority(int newPriority) 更改线程的优先级
int getPriority() 返回线程的优先级。
static int MAX_PRIORITY
线程可以具有的最高优先级。
static int MIN_PRIORITY
线程可以具有的最低优先级。
static int NORM_PRIORITY
分配给线程的默认优先级。

package com.shsxt.threadstate;

import java.lang.Thread.State;

public class ThreadState03 implements Runnable{
	public static void main(String[] args) {
		Thread th = new Thread(()->{
			for(int i=1;i<10;i++){
				if(i==5){
					try {
						Thread.sleep(100);
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					};
				}
			}
		});
		System.out.println(th.getState());
		th.start();
		System.out.println(th.getState());
		while(true){
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			System.out.println(th.getState());
			if(th.getState()==State.TERMINATED){//状态是枚举类型 需要用类名点的形式使用
				System.out.println(Thread.currentThread().getName()+"当前线程的状态是"+th.getState());
				break;
			}
		}
		
		Thread th01 = new Thread(new ThreadState03(),"A");
		Thread th02 = new Thread(new ThreadState03(),"B");
		Thread th03 = new Thread(new ThreadState03(),"C");
		th01.setPriority(Thread.MIN_PRIORITY);
		th02.setPriority(Thread.MAX_PRIORITY);
		th03.setPriority(Thread.NORM_PRIORITY);
		th01.start();
		th02.start();
		th03.start();
	}

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

同步锁

synchronized

  • 使用方法
  • 1.使用在代码块上
  • 2.使用在方法上
    可以锁的内容:
    **this(调用当前这个方法的对象,**this关键字必须在方法里使用,因为方法只有被调对象调用才会执行,只有在调用方法对象才能是已经生成了的.而static修饰的方法是类的,在类加载的时候就存在于静态方法区不需要对象,所以不能再static方法里面使用this,但是可以创建对象来调用该对象的成员方法,比如:new Object().method())
    类名.class(当前这个类的class对象,锁上后该类的所有对象都不能使用)
    资源(引用数据类型的成员属性(某个类的成员属性是一个另一个类))
    wait()执行后会释放出对象 其他线程可以使用,并不是自己不用别人也不能使用
    人和车过斑马线例子
package com.shsxt.threadstate;

public class Threadwait04 {
	public static void main(String[] args) {
		Street street = new Street();
		new Thread(new Person(street)).start();
		new Thread(new Car(street)).start();
	}
}

class Street {
	boolean flag = false;
	
	//人走
	public synchronized void ns() throws InterruptedException{
		if(flag==false){
			this.wait();
		}else{
			System.out.println("人走");
			flag = false;
			this.notify();
		}
	}
	//车走
	public synchronized void we() throws InterruptedException{//IllegalMonitorStateException
		if(flag==true){
			this.wait();
		}else{
			System.out.println("车走");
			flag = true;
			this.notify();
		}
	}
}

class Person implements Runnable{
	Street street;
	//要用带street的方法
	
	@Override
	public void run() {
		while(true){
			try {
				street.ns();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
	public Person() {
		super();
	}
	public Person(Street street) {
		super();
		this.street = street;
	}
	
}

class Car implements Runnable{
	Street street;
	
	public Car() {
		super();
	}

	public Car(Street street) {
		super();
		this.street = street;
	}

	@Override
	public void run() {
		while(true){
			try {
				street.we();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	
		
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值