Java的基础复习(12-5)

Java的基础复习(12-5)

文章目录


类和方法

方法修饰符

1.访问控制修饰符

公共访问控制符public、保护访问控制符protected、缺省默认访问控制符、私有访问控制符private

2.非访问控制修饰符

抽象方法控制符abstract 、静态方法控制符static 、最终方法控制符final 、本地方法控制符native 、同步方法控制符synchronized

访问控制修饰符的访问权限

访问级别访问控制修饰符同类同包子类(不同包)不同包(其他类)
公共public
受保护protected×
默认缺省修饰符××
私有private×××

引用类型(4种)

为了解决内存泄漏的问题,通过四种引用类型强行调用垃圾回收方法 System.gc() 来解决内存泄漏问题

  1. 强引用 显式执行 object=null 语句

  2. 软引用 内存不足时回收对象占用的空间 referent - 新的软引用将引用的对象 q - 该引用向其注册的队列,如果不需要注册,则为 null

  3. 弱引用 对象拥有更短的生命周期 直接回收被弱引用了的对象 WeakReference

  4. 虚引用 结合引用关联队列,实现对对象引用关系的跟踪 PhantomReference

使用 instanceof 运算符

二元运算符,测试左边的对象是否是右边类的实例,返回值 boolean

public class test {
	public static void main(String[] args) {
		System.out.println("string" instanceof Object);  //true
	}
}

枚举类型

1.5以后 enum

public class test {
	
	public enum Color{
		red,blue,yellow,pink,black,white,purple,
	}
	
	public static void main(String[] args) {
		judje(Color.red);
	}

	private static void judje(Color color) {
		switch (color) {
		case red:
			System.out.println("red");
			break;
		case blue:
			System.out.println("blue");
		default:
			System.out.println("other");
			break;
		}	
	}
}

泛型

作用: ①数据的安全,约定数据的类型;② 防止类型出错

HashMap<String, Integer> hashMap = new HashMap<>();

比较器

集合、列表的sort()只能自然排序

内部比较

  • 实现Comparable接口,重写compareTo方法
  • 1: 当前大 0:一样大 -1: 传入的大
public class Student implements MyInterface, Comparable<Object> {
    .....
   //根据电话降序
   	@Override
	public int compareTo(Object o) {
		Student student = (Student) o;
		return this.phone < student.phone ? 1 : (this.phone == student.phone ? 0 : -1);
	}
  • 多级排序
	@Override
	public int compareTo(Object o) {
//		根据phone id降序
		Student student = (Student) o;
		int result = this.phone < student.phone ? 1 : (this.phone == student.phone ? 0 : -1);
		if (result == 0) {
//		string重写了比较方法,默认升序
			result = -this.id.compareTo(student.id);
		}
		return result;
	}

外部比较

无侵入性,不需要修改原有的代码

  • 定义一个外部比较器,实现Comparator接口
public class MyConparatorWithPhone implements Comparator<Object> {

	@Override
	public int compare(Object o1, Object o2) {
		Student s1 = (Student) o1;
		Student s2 = (Student) o2;
		return s1.getPhone() - s2.getPhone();
	}
}

  • 使用
Collections.sort(list, new MyConparatorWithPhone());

自动装箱与自动拆箱

**自动装箱: ** 基本类型—》包装类型 valueOf()

**自动拆箱: ** intValue() 有一个缓冲区 [-128,127] 不在缓冲区范围内就new

数组

package com.gen.test;

import java.util.Arrays;

public class Main {
	public static void main(String[] args) {
		int[] array1 = { 10, 50, 30, 40 };
		int[] array2 = { 10, 50, 30, 40 };
		int[] array3 = { 10, 50, 30 };
		System.out.println(Arrays.equals(array1, array2));
		System.out.println(Arrays.equals(array1, array3));
//		默认的是按照升序排序
		Arrays.sort(array1);
		System.out.println(Arrays.toString(array1));
//		将数组的所有元素赋值为相同的值
		Arrays.fill(array3, 100);
		System.out.println(Arrays.toString(array3));
//		将数组的长度复制成为一个长度为设定值的新数组
		int[] copyOf = Arrays.copyOf(array1, 2);
		System.out.println(Arrays.toString(copyOf));
		int[] copyOf2 = Arrays.copyOf(array3, 6);
		System.out.println(Arrays.toString(copyOf2));
		Arrays.sort(array2);
		System.out.println(Arrays.binarySearch(array2, 30));
	}
}
true
false
[10, 30, 40, 50]
[100, 100, 100]
[10, 30]
[100, 100, 100, 0, 0, 0]
1

常用集合

Collection 接口的接口 对象的集合(单列集合)

├——-List 接口:元素按进入先后有序保存,可重复
│—————-├ LinkedList 接口实现类, 链表, 插入删除, 没有同步, 线程不安全
│—————-├ ArrayList 接口实现类, 数组, 随机访问, 没有同步, 线程不安全
│—————-└ Vector 接口实现类 数组, 同步, 线程安全 实现自动增长的对象数组
│ ———————-└ Stack 是Vector类的实现类
└——-Set 接口: 仅接收一次,不可重复,并做内部排序
├—————-└HashSet 使用hash表(数组)存储元素
│————————└ LinkedHashSet 链表维护元素的插入次序
└ —————-TreeSet 底层实现为二叉树,元素排好序

Map 接口 键值对的集合 (双列集合)

├———Hashtable 接口实现类, 同步, 线程安全
├———HashMap 接口实现类 ,没有同步, 线程不安全
│—————–├ LinkedHashMap 双向链表和哈希表实现
│—————–└ WeakHashMap
├ ——–TreeMap 红黑树对所有的key进行排序
└———IdentifyHashMap

通过迭代器 Iterator 遍历Map集合

package com.gen.test;

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

import com.gen.entity.Student;

public class TestMap {
	public static <V> void main(String[] args) {
		Student student1 = new Student("12", "zhangsan");
		Student student2 = new Student("13", "lisi");
		Student student3 = new Student("14","wangwu");
		Student student4 = new Student("15", "zhaoliu");
		Map<String,Object> map = new HashMap<String, Object>();
		map.put(student1.getId(), student1);
		map.put(student2.getId(), student2);
		map.put(student3.getId(), student3);
		map.put(student4.getId(), student4);
		
		Iterator<String> iterator = map.keySet().iterator();
//		取出所有key的集合
		while(iterator.hasNext()) {
			String key = iterator.next();
			System.out.println(map.get(key));
		}

		for (Object key : map.keySet()) {
			System.out.println(map.get(key));
		}
	}
}
Student [id=12, name=zhangsan]
Student [id=13, name=lisi]
Student [id=14, name=wangwu]
Student [id=15, name=zhaoliu]
Student [id=12, name=zhangsan]
Student [id=13, name=lisi]
Student [id=14, name=wangwu]
Student [id=15, name=zhaoliu]

异常

throw new Exception() 自定义类型异常

	public void setId(String id) throws Exception {
		if (id.length() < 4 || id.length() > 10) {
			throw new Exception("the length of id must 4-10,the giving length is " + id.length());
		} else {
			this.id = id;
		}

	}
package com.gen.test;

import com.gen.entity.Student;

public class TestException {
	public static void main(String[] args) {
		Student student = new Student();
		try {
			student.setId("123");
			student.setName("zhangsan");
		} catch (Exception e) {
			System.err.println(e.getMessage());
		} finally {
			System.out.println("end.....");
		}
	}
}
the length of id must 4-10,the giving length is 3
end.....

异常的分类

描述
Throwable所有异常的父类
Error虚拟机抛出的异常
Exception应用程序抛出和处理的非严重错误
RuntimeException输出异常的堆栈信息并终止程序运行
Checked没有继承或者抛出异常,编译错误

自定义异常

1.继承 Exception 或者 RuntimeException

2.编写异常类的构造方法,并继承父类实现

package com.gen.exception;

public class NameException extends Exception {
	public NameException() {
	}
	public NameException(String msg) {
		super(msg);
	}
}
	public void setName(String name) throws NameException {
		if (name.length() < 3 || name.length() > 5) {
			throw new NameException("the length of name must be 3-5 the acutal is " + name.length());
		} else {
			this.name = name;
		}
	}
package com.gen.test;

import com.gen.entity.Student;

public class TestNameException {
	public static void main(String[] args) {
		Student student = new Student();
		try {
			student.setId("1234");
			student.setName("aa");
			System.out.println(student);
		} catch (Exception e) {
			System.err.println(e.getMessage());
		} finally {
			System.out.println("finished.....");
		}
	}
}
the length of name must be 3-5 the acutal is 2
finished.....

log4j记录日志的使用

1.log4j.properties

log4j.rootLogger = debug,stdout,D,E
 
### print info on console ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
 
### debug info to debugfile ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D://eclipse-workspace/WEB/Test/src/log/debug.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
 
### error info to errorfile ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File = D://eclipse-workspace/WEB/Test/src/log/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR 
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
  1. TestLog.java
package com.gen.test;

import java.util.InputMismatchException;
import java.util.Scanner;

import org.apache.log4j.Logger;

public class TestLog {
	private static Logger logger = Logger.getLogger(TestLog.class.getName());

	@SuppressWarnings("resource")
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		try {
			System.out.print("input a: ");
			int a = scanner.nextInt();
			logger.debug("input a " + a);
			System.out.print("input b: ");
			int b = scanner.nextInt();
			logger.debug("input b: " + b);
			System.out.printf("%d /%d =%d\n", a, b, a / b);
			logger.debug("ouput info " + String.format("%d /%d =%d\n", a, b, a / b));
		} catch (InputMismatchException e) {
			logger.error("a,b must be integer" + e);
		} catch (ArithmeticException e) {
			logger.error(e.getMessage());
		} finally {
			System.out.println("welcome to use....");
		}
	}
}
2021-03-23 18:24:38  [ main:0 ] - [ DEBUG ]  input a 10
2021-03-23 18:24:39  [ main:809 ] - [ DEBUG ]  input b: 2
2021-03-23 18:24:39  [ main:818 ] - [ DEBUG ]  ouput info 10 /2 =5

2021-03-23 18:28:18  [ main:0 ] - [ DEBUG ]  input a 12
2021-03-23 18:28:19  [ main:1387 ] - [ DEBUG ]  input b: 0
2021-03-23 18:28:19  [ main:1390 ] - [ ERROR ]  / by zero

抽象类和接口

抽象方法: 方法不会有具体的实现实例化,而是抽象类的子类中重写实现;抽象方法被子类使用——代码复用;抽象方法——子类自身的独特性 不能多继承

接口: 提供一种约定(U盘),表示一种能力(软件工程师,设计师) extends 单继承 implements 多接口

文件操作

File对象不仅能表示文件,也能表示目录

操作目录或文件的属性

获得文件的信息
String filePath = "D:\\log\\debug.log";
File file = new File(filePath);
if (file.exists()) {
    if (file.isFile()) {
        System.out.println(file.isDirectory());
        System.out.println("相对路径: " + file.getPath());
        System.out.println("绝对路径: " + file.getAbsolutePath());
        System.out.println("文件或目录的名称:" + file.getName());
        System.out.println("文件长度(单位:字节):" + file.length());
    }
}
false
相对路径: D:\log\debug.log
绝对路径: D:\log\debug.log
文件或目录的名称:debug.log
文件长度(单位:字节):361
创建文件
String filePath = "D:\\log\\debug1.log";
File file = new File(filePath);
if (!file.exists()) {
    try {
        file.createNewFile();
        System.out.println("create file successfully!");
    } catch (IOException e) {
        e.printStackTrace();
    }
}
删除文件
String filePath = "D:\\log\\debug1.log";
File file = new File(filePath);
if (file.exists()) {
    file.delete();
    System.out.println("file deleted!");
}

Java IO流

数据输入输出的抽象

按照处理数据单元划分:

  • ​ 字节流:

​ InputStream / OutputStream

  • ​ 字符流:

​ Reader / Writer

字节流读文本文件

1.字节输入流 InputStream 类 文件的数据输入内存
2.字节输入流 FileInputStream
3.FileInputStream 类读取文本文件
String path = "src/com/gen/test/file/a.txt";
File file = new File(path);
FileInputStream in = null;
FileOutputStream out = null;

StringBuffer buffer = new StringBuffer();
try {
    in = new FileInputStream(file);
    byte[] buf = new byte[in.available()];
    //			将文件的内容读到buf中
    in.read(buf);
    System.out.println(new String(buf));
} catch (IOException e) {
    e.printStackTrace();
}finally {
    try {
        in.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

字节流写文本文件

1.字节输出流 OutputStream 类 数据从内存输入到文件
2.字节输出流 FileOutputStream
3.FileOutputStream 类写文本文件
String path = "src/com/gen/test/file/a.txt";
FileInputStream in = new FileInputStream(path);

String path1 = "src/com/gen/test/file/b.txt";
FileOutputStream out = new FileOutputStream(path1);
byte [] buf = new byte[10];
int len = -1;
while((len=in.read(buf))!=-1) {
    out.write(buf, 0, len);
}
System.out.println("finished!");
out.close();
in.close();
System.exit(0);

字符流读文本文件

字符输入流 Reader FileReader
		FileReader fileReader = null;
		String pathname = "D:\\log\\a.txt";
		try {
			fileReader = new FileReader(new File(pathname));
//			创建字符数组作为中转站
			char[] cbuf = new char[1024];
			StringBuffer buffer = new StringBuffer();
			int length;
			while ((length = fileReader.read(cbuf)) != -1) {
				buffer.append(cbuf);
			}
			System.out.println(buffer.toString());
		} 
字符输入流 BufferedReader

带有缓冲区,每次把数据读到缓冲区,接着在缓冲区读取数据,避免每次从数据源读取数据进行编码转换

		String pathname = "D:\\\\log\\\\a.txt";
		BufferedReader bufferedReader = null;
		try {
			bufferedReader = new BufferedReader(new FileReader(new File(pathname)));
			String line = null;
			StringBuffer stringBuffer = new StringBuffer();
			while ((line = bufferedReader.readLine()) != null) {
				stringBuffer.append(line);
			}
			System.out.println(stringBuffer.toString());
        }

字符流写文本文件

字符输出流 Writer FileWriter
		String context = "hello world! 世根1111";
		String pathname = "D:\\log\\a.txt";
		FileWriter fileWriter = null;
		try {
			fileWriter = new FileWriter(new File(pathname));
			fileWriter.write(context);
			System.out.println("finished!");
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				fileWriter.close();
				System.exit(0);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
字符输出流 BufferedWriter
		String context = "hello world! 世根1";
		String pathname = "D:\\log\\a.txt";
		BufferedWriter bufferedWriter = null;
		try {
			bufferedWriter = new BufferedWriter(new FileWriter(new File(pathname)));
			bufferedWriter.write(context);
			System.out.println("finished!");
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				bufferedWriter.close();
				System.exit(0);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

读写二进制文件

DataInputStream DataOutputStream

序列化和反序列化

便于将字段和属性保存到磁盘中并从磁盘中还原

序列化概述

将对象的信息转化为字节序列;二进制形态,实现了跨平台特性

序列化保存对象信息
public class Student implements Serializable{
		ObjectOutputStream objectOutputStream = null;
		String pathname = "D:\\log\\serializable.txt";
		try {
			objectOutputStream = new ObjectOutputStream(
					new ObjectOutputStream(new FileOutputStream(new File(pathname))));
						Student student = new Student("111", "zhangsan");
			Student student2 = new Student("222", "lisi");
			List<Student> list = new ArrayList<Student>();
			list.add(student);
			list.add(student2);
            // 把List序列化
			objectOutputStream.writeObject(list);
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				objectOutputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
反序列化获得对象信息
		ObjectInputStream objectInputStream = null;
		String pathname = "D:\\log\\serializable.txt";
		try {
			objectInputStream = new ObjectInputStream(new FileInputStream(new File(pathname)));
			List<Student> list = (ArrayList<Student>) objectInputStream.readObject();
			for (Student student : list) {
				System.out.println(student);
			}
			System.exit(0);
		} catch (IOException | ClassNotFoundException e) {

Java组件

事件处理总结:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zXif1TXj-1617449335789)(C:\Users\ShiGen\Desktop\2020-12-06_201000.png)]

AWT组件库

  1. Button
  2. Checkbox
  3. CheckboxGroup
  4. Choice
  5. Canvas 创建自定义组件
  6. TextField
  7. TextArea
  8. List
  9. Frame
  10. Dialog
  11. Filedialog
  12. Menu
  13. MenuBar
  14. Menu 添加到MenuBar中成为下拉菜单
  15. MenuItem

注解和多线程

注解的分类

注解解释
内建注解
@Override重写父类的某些方法
@Deprecated标注程序元素已过时
@SuppressWarnings标识阻止编译器警告,有选择的关闭编译器对类、方法和成员变量等程序元素及其子元素的警告
元注解
@Target指定被其修饰的注解能用于修饰哪些程序元素
@Rentention描述了被其修饰的注解是否被编译器丢弃或者保留在class文件中
@Documented指定被其修饰的注解将被javaDoc工具提取成文档
@Inherited指定被其修饰的注解将具有继承性

多线程

线程: 是进程的一个顺序执行流,为进程执行的多条线索,是调度和执行的基本单位

改善应用程序:

  1. 充分利用CPU资源——某一个线程发生休眠或阻塞时,CPU恰好处于空闲状态运行其他线程

  2. 简化编程模型——简化系统(12306购票),易于维护

  3. 简化异步事件的处理——客户端和服务器建立连接

  4. 使GUI更有效率

    Java多线程的创建以及启动

  5. 继承 Thread

  6. 实现 Runable 接口(开发中使用最多)

  7. 使用 ExecutorService Callable Future 实现


	public static void main(String[] args) {
		for(int i=0;i<4;i++) {
			System.out.println(Thread.currentThread().getName()+"-"+i);
			if(i==2) {
				MyThread myThread1 = new MyThread();
				MyThread myThread2 = new MyThread();
				myThread1.start();
				myThread2.start();
			}
		}
	}

class MyThread extends Thread{
	@Override
	public void run() {
		for(int i=0;i<4;i++) {
			System.out.println(Thread.currentThread().getName()+"--"+i);
		}
	}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FgjHx6cl-1617449335794)(C:\Users\ShiGen\AppData\Roaming\Typora\typora-user-images\image-20201206205431757.png)]

	public static void main(String[] args) {
		for(int i=0;i<4;i++) {
			System.out.println(Thread.currentThread().getName()+"-"+i);
			if(i==2) {
				MyRunnable myRunnable = new MyRunnable();
				Thread thread1 = new Thread(myRunnable);
				Thread thread2 = new Thread(myRunnable);
				thread1.start();
				thread2.start();
			}
		}
	}

class MyRunnable implements Runnable{
	@Override
	public void run() {
		for(int i=0;i<4;i++) {
			System.out.println(Thread.currentThread().getName()+"--"+i);
		}
	}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2c8Px43f-1617449335799)(C:\Users\ShiGen\AppData\Roaming\Typora\typora-user-images\image-20201206210306003.png)]

public class Test2 {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		System.out.println("program starting......");
		Date date1 = new Date();
		int taskSize = 5;
//		创建一个线程池
		ExecutorService pool = Executors.newFixedThreadPool(taskSize);
//		创建有多个返回值的任务
		List<Future> list = new ArrayList<Future>();
		for(int i=0;i<5;i++) {
			MyCallable c = new MyCallable(i+"");
//			执行任务 获取 Future对象
			Future future = pool.submit(c);
			list.add(future);
		}
//		关闭线程池
		pool.shutdown();
//	获取所有并发任务地结果
		for(Future future : list) {
//			从对象上获取任务的返回值
			System.out.println(future.get().toString());
		}
		Date date2 = new Date();
		System.out.println("start to end use "+(date2.getTime()-date1.getTime())+"ms");
	}

}

class MyCallable implements Callable<Object>{
	private String taskNum;
	
	MyCallable(String taskNum){
		this.taskNum = taskNum;
	}
	
	@Override
	public Object call() throws Exception {
		System.out.println(taskNum+" start......");
		Date dateTemp1 = new Date();
		Thread.sleep(1000);
		Date deteTemp2 = new Date();
		long time = deteTemp2.getTime()-dateTemp1.getTime();
		System.out.println(taskNum+" end......");
		return taskNum+" "+time+"ms";
	}
	
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TwKSSQUs-1617449335818)(C:\Users\ShiGen\AppData\Roaming\Typora\typora-user-images\image-20201206212605060.png)]

Java多线程的优先级和调度
public static final int MAX_PRIORITY 10
public static final int MIN_PRIORITY 1
public static final int NORM_PRIORITY 5
线程优先级的一些特性: Priority

1)线程优先级的无序性:线程优先级有随机的特性
2)线程优先级的继承性:继承关系中优先级一样,线程A启动线程B,那么A线程和B线程的优先级一样
3)线程优先级的规则性:线程会按优先级的大小顺序执行,但并不代表优先级大的一定先执行

调度线程的策略: 抢占式调度策略 时间片轮转调度策略(先调用优先级高的线程)

多线程的线程控制

1.join线程 让一个线程等待另一个线程完成的方法

	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			if (i == 5) {
				MyThread temp = new MyThread();
				try {
					temp.start();
					temp.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			System.out.println(Thread.currentThread().getName() + "---" + i);
		}
	}

class MyThread extends Thread {
	@Override
	public void run() {
		for (int i = 0; i < 5; i++) {
			System.out.println(Thread.currentThread().getName() + "--" + i);
		}
	}
}
main---0
......
main---4
Thread-0--0
......
Thread-0--4
main---5
......
main---9

2.后台线程 在后台运行性,为其他线程提供服务(JVM垃圾回收器)–前台的进程死亡,后台的进程也死亡

3.线程休眠 sleep 当前线程暂停一段时间,进入阻塞状态,之后进入可运行状态

// main方法
		System.out.println("waiting......");
		Wait.waitBySec(5);
		System.out.println("finished.....");
——————————————————————————————————————————————————————
class Wait {
	public static void waitBySec(int seconds) {
		for (int i = 0; i < seconds; i++) {
			System.out.println("waiting " + (i + 1) + "s");
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}    
waiting......
waiting 1s
waiting 2s
waiting 3s
waiting 4s
waiting 5s
finished.....

4.线程让步 yield 也可以暂停当前的线程 使线程转入就绪状态;此时,系统选择其它相同或更高优先级线程执行;若无,该线程继续执行

		FirstThread firstThread = new FirstThread();
		SecondThread secondThread = new SecondThread();
		firstThread.start();
		secondThread.start();
————————————————————————————————————
class FirstThread extends Thread{
	@Override
	public void run() {
		for(int i=0;i<5;i++) {
			System.out.println(Thread.currentThread().getName()+"----"+(i+1));
			Thread.yield();
		}
	}
}

class SecondThread extends Thread{
	@Override
	public void run() {
		for(int i=0;i<5;i++) {
			System.out.println(Thread.currentThread().getName()+"----"+(i+1));
			Thread.yield();
		}
	}
}
Thread-1----1
Thread-0----1
......
Thread-1----5
Thread-0----5

sleepyield 的区别:

①sleep方法给其他线程运行机会时不考虑线程的优先级,因此会给低线程优先级运行的机会,而yield方法只会给相同优先级或者更高优先级线程运行的机会

②线程执行sleep()方法后转入阻塞状态,所以,执行sleep()方法的线程在指定的时间内不会被执行;而yield()方法只是使当前线程重新回到可执行状态,所以执行yield()方法的线程可能在进入可执行状态后马上又被执行

③sleep()方法声明抛出InterruptedException,而yield()方法没有声明任何异常

④sleep()方法比yield()方法(跟操作系统相关)有更好的可移植性

线程同步

运行的线程需要共享数据

同步代码块

synchronized(object){} 语句块会自动加上内置锁,实现线程的同步

高开销的动作,应尽量减少同步的内容

同步方法

public synchronized void run(){} 同步锁只能是this 或者当前类的字节码对象

代码案例
package com.gen.test.Thread;

public class TestSynchronized {
	public static void main(String[] args) {
		TestAccount t = new TestAccount();
		Thread one = new Thread(t);
		Thread two = new Thread(t);
		one.setName("张三");
		two.setName("张三妻子");
//		启动线程
		one.start();
		two.start();
	}
}

class Account {
	private int balance = 500;

	public int getBalance() {
		return balance;
	}

	public void withdraw(int amount) {
		this.balance = this.balance - amount;
	}
}

class TestAccount implements Runnable {
	private Account account = new Account();

	@Override
	public void run() {
		for (int i = 0; i < 5; i++) {
			makeWithdrawal(100);
			if (account.getBalance() < 0) {
				System.out.println("账户透支了!!!");
			}
		}
	}

	private void makeWithdrawal(int amt) {
		if (account.getBalance() >= amt) {
			System.out.println(Thread.currentThread().getName() + "准备取款 " + amt);
//		0.5后实现取款
			try {
				Thread.sleep(500);
				account.withdraw(amt);
				System.out.println(
						Thread.currentThread().getName() + "完成取款,取出 " + amt + " 元,余额为: " + account.getBalance());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} else {
//			余额不足的提示
			System.out.println("操作失败: " + Thread.currentThread().getName() + " 余额为: " + account.getBalance());
		}

	}
}
--------------------------------------------
张三准备取款 100
张三妻子准备取款 100
张三完成取款,取出 100 元,余额为: 400
张三准备取款 100
张三妻子完成取款,取出 100 元,余额为: 300
张三妻子准备取款 100
张三完成取款,取出 100 元,余额为: 200
张三准备取款 100
张三妻子完成取款,取出 100 元,余额为: 100
张三妻子准备取款 100
张三完成取款,取出 100 元,余额为: -100
张三妻子完成取款,取出 100 元,余额为: -100
账户透支了!!!
操作失败: 张三妻子 余额为: -100
账户透支了!!!
操作失败: 张三妻子 余额为: -100
账户透支了!!!
账户透支了!!!
操作失败: 张三 余额为: -100
账户透支了!!!
操作失败: 张三 余额为: -100
账户透支了!!!
  • 同步方法
package com.gen.test.Thread;

public class TestSynchronized {
	public static void main(String[] args) {
		TestAccount t = new TestAccount();
		Thread one = new Thread(t);
		Thread two = new Thread(t);
		one.setName("张三");
		two.setName("张三妻子");
//		启动线程
		System.out.println("--------------------------------------------");
		one.start();
		two.start();
	}
}

class Account {
	private int balance = 500;

	public int getBalance() {
		return balance;
	}

	public void withdraw(int amount) {
		this.balance = this.balance - amount;
	}
}

class TestAccount implements Runnable {
	private Account account = new Account();

	@Override
	public void run() {
		for (int i = 0; i < 5; i++) {
			makeWithdrawal(100);
			if (account.getBalance() < 0) {
				System.out.println("账户透支了!!!");
			}
		}
	}

	private synchronized void makeWithdrawal(int amt) {
		if (account.getBalance() >= amt) {
			System.out.println(Thread.currentThread().getName() + "准备取款 " + amt);
//		0.5后实现取款
			try {
				Thread.sleep(500);
				account.withdraw(amt);
				System.out.println(
						Thread.currentThread().getName() + "完成取款,取出 " + amt + " 元,余额为: " + account.getBalance());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} else {
//			余额不足的提示
			System.out.println("操作失败: " + Thread.currentThread().getName() + " 余额为: " + account.getBalance());
		}

	}
}
--------------------------------------------
张三准备取款 100
张三完成取款,取出 100 元,余额为: 400
张三妻子准备取款 100
张三妻子完成取款,取出 100 元,余额为: 300
张三准备取款 100
张三完成取款,取出 100 元,余额为: 200
张三妻子准备取款 100
张三妻子完成取款,取出 100 元,余额为: 100
张三准备取款 100
张三完成取款,取出 100 元,余额为: 0
操作失败: 张三妻子 余额为: 0
操作失败: 张三妻子 余额为: 0
操作失败: 张三妻子 余额为: 0
操作失败: 张三 余额为: 0
操作失败: 张三 余额为: 0
  • 同步代码块
package com.gen.test.Thread;

public class TestSynchronized {
	public static void main(String[] args) {
		TestAccount t = new TestAccount();
		Thread one = new Thread(t);
		Thread two = new Thread(t);
		one.setName("张三");
		two.setName("张三妻子");
//		启动线程
		System.out.println("--------------------------------------------");
		one.start();
		two.start();
	}
}

class Account {
	private int balance = 500;

	public int getBalance() {
		return balance;
	}

	public void withdraw(int amount) {
		this.balance = this.balance - amount;
	}
}

class TestAccount implements Runnable {
	private Account account = new Account();

	@Override
	public void run() {
		for (int i = 0; i < 5; i++) {
			makeWithdrawal(100);
			if (account.getBalance() < 0) {
				System.out.println("账户透支了!!!");
			}
		}
	}

	private void makeWithdrawal(int amt) {
		synchronized (account) {
			if (account.getBalance() >= amt) {
				System.out.println(Thread.currentThread().getName() + "准备取款 " + amt);
//		0.5后实现取款
				try {
					Thread.sleep(500);
					account.withdraw(amt);
					System.out.println(
							Thread.currentThread().getName() + "完成取款,取出 " + amt + " 元,余额为: " + account.getBalance());
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} else {
//			余额不足的提示
				System.out.println("操作失败: " + Thread.currentThread().getName() + " 余额为: " + account.getBalance());
			}
		}
	}
}
--------------------------------------------
张三准备取款 100
张三完成取款,取出 100 元,余额为: 400
张三妻子准备取款 100
张三妻子完成取款,取出 100 元,余额为: 300
张三准备取款 100
张三完成取款,取出 100 元,余额为: 200
张三妻子准备取款 100
张三妻子完成取款,取出 100 元,余额为: 100
张三准备取款 100
张三完成取款,取出 100 元,余额为: 0
操作失败: 张三妻子 余额为: 0
操作失败: 张三妻子 余额为: 0
操作失败: 张三妻子 余额为: 0
操作失败: 张三 余额为: 0
操作失败: 张三 余额为: 0

问题: 多线程在使用同步机制时,存在“死锁”(多个线程处于等待状态—占用资源,无法运行 无法唤醒)潜在危险

避免方法: ①线程因某个条件未满足而受阻,释放其资源;②若多个对象需互斥访问,确定线程获得锁的先后顺序,整个程序以相反的顺序释放锁

使用特殊域变量(volatile)实现线程同步

使用该域要重新计算 可能导致死锁的状态

volatile和synchronized的区别

  • volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
  • volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
  • volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
  • volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
  • volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化
使用重入锁实现线程的同步

ReentrantLock synchronized

最大的作用是避免死锁

使用局部变量实现线程同步

如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。

ThreadLocal 类的常用方法 为每个线程提供一个独立的变量副本解决变量并发访问的冲突问题

ThreadLocal() : 创建一个线程本地变量 
get() : 返回此线程局部变量的当前线程副本中的值 
initialValue() : 返回此线程局部变量的当前线程的"初始值" 
set(T value) : 将此线程局部变量的当前线程副本中的值设置为value

线程间的通信

解决生产者和消费者之间的问题

wait()当前线程释放锁并进入等待(阻塞)状态 运行状态——等待队列
notify()唤醒一个正在等待响应对象锁的线程,使其进入就绪队列,以便在当前线程释放锁后继续竞争锁
notifyAll()唤醒所有正在等待响应对象锁的线程,使其进入就绪队列,以便在当前线程释放锁后继续竞争锁
  • 使用wait()、notify()和notifyAll()需要先调用对象加锁
  • 调用wait()方法后,线程状态由Running变成Waiting,并将当前线程放置到对象的等待队列
  • notify()和notifyAll()方法调用后,等待线程依旧不会从wait()返回,需要调用notify()和notifyAll()的线程释放锁之后等待线程才有机会从wait()返回
  • notify()方法将等待队列中的一个等待线程从等待队列中移到同步队列中,而notifyAll()方法则是将等待队列中所有的线程全部转移到同步队列,被移到的线程状态由Waiting变为Blocked。
  • 从wait()方法返回的前提是获得调用对象的锁
package com.gen.test;


/**
 * @ClassName : CommunicateThread
 * @Author : ShiGen
 * @Date: 2021/3/27 15:04
 * @Description : ${description}
 */

public class CommunicateThread implements Runnable {

    public static void main(String[] args){
        CommunicateThread communicateThread = new CommunicateThread ( );
        Thread threada = new Thread ( communicateThread, "线程a" );
        Thread threadb = new Thread ( communicateThread, "线程b" );
        threada.start ( );
        threadb.start ( );
    }

    @Override
    synchronized public void run( ){
        for(int i = 0; i < 5; i++){
            System.out.println ( Thread.currentThread ( ).getName ( ) + "-----" + i );
            if(i==2){
                try{
                    wait ( );
                } catch(InterruptedException e){
                    e.printStackTrace ( );
                }
            }
            if(i==1){
                notify ( );
            }
            if(i==4){
                notifyAll ( );
            }
        }
    }
}
"D:\Program Files\Java\jdk1.8.0_241\bin\java.exe" "-javaagent:D:\JetBrains\IntelliJ IDEA 
线程a-----0
线程a-----1
线程a-----2
线程b-----0
线程b-----1
线程b-----2
线程a-----3
线程a-----4
线程b-----3
线程b-----4
线程通信解决生产者消费者问题
package com.gen.test;


/**
 * @ClassName : CommunicationDemo
 * @Author : ShiGen
 * @Date: 2021/3/27 16:38
 * @Description : ${description}
 */
public class CommunicationDemo {
    public static void main(String[] args){
        sharedResores sharedResores = new sharedResores ( );
        new Consuer ( sharedResores ).start ( );
        new Producer ( sharedResores ).start ( );
    }
}

class sharedResores {
    private char c;
    //    标记还没有生产
    private boolean isProduced = false;

    synchronized void putShareChar(char c){
  /*      没生产是因为消费者还没有消费——等待
        生产了唤醒消费者消费
        */
//      没有在生产是因为在等待消费
        if(isProduced){
            try{
                System.out.println ( "没有消费,生产者停止生产" );
                wait ( );
            } catch(InterruptedException e){
                e.printStackTrace ( );
            }
        }
        this.c = c;
//        已经生产了,通知消费者
        isProduced = true;
        notify ( );
        System.out.println ( "生产了 " + c + " 消费者来消费" );
    }

//    同步的方法获得当前的资源
    synchronized char getShareChar( ){
        if(!isProduced){
            try{
                System.out.println ( "生产者正在生产,等待一伙儿" );
                wait ( );
            } catch(InterruptedException e){
                e.printStackTrace ( );
            }
        }
        isProduced = false;
        notify ( );
        System.out.println ( "消费了 " + c + " 通知生产者生产" );
        return this.c;
    }
}

class Producer extends Thread {
    private sharedResores sharedResores;

    Producer(sharedResores sharedResores){
        this.sharedResores = sharedResores;
    }

    @Override
    public void run( ){
        for(char ch = 'A'; ch <= 'D'; ch++){
            try{
                Thread.sleep ( (int) (Math.random ( ) * 3000) );
            } catch(InterruptedException e){
                e.printStackTrace ( );
            }
            sharedResores.putShareChar ( ch );
        }
    }
}

class Consuer extends Thread {
    private sharedResores sharedResores;

    Consuer(sharedResores sharedResores){
        this.sharedResores = sharedResores;
    }

    @Override
    public void run( ){
        char ch = ' ';
        while(ch!='D'){
            try{
                Thread.sleep ( (int) (Math.random ( ) * 3000) );
            } catch(InterruptedException e){
                e.printStackTrace ( );
            }
            ch = sharedResores.getShareChar ( );
        }
    }
}

生产了 A 消费者来消费
消费了 A 通知生产者生产
生产了 B 消费者来消费
消费了 B 通知生产者生产
生产了 C 消费者来消费
消费了 C 通知生产者生产
生产了 D 消费者来消费
消费了 D 通知生产者生产
线程通信的其它方法

1.中断线程 interrupt() 冻结状态——>运行状态

2.守护线程 setDaemon() main线程结束,后台线程也结束

3.join() A线程执行到B线程的join()方法,A就放弃运行资格,处于冻结等待状态,等B线程执行完,A才恢复运行资格;B线程运行中挂掉,A线程用interrupt()清理A线程的冻结状态;join()用来临时加入线程执行

4.yield() 暂时释放执行资格,稍稍减缓线程的切换频率,让多个线程得到的运行资格均等一些

反射机制

运行的过程中,动态获取信息、动态调用对象方法的功能

获取类的信息

1.获取Class对象
//    调用对象的getClass()方法
        Student student = new Student ( );
        System.out.println ( student.getClass ( ) );
//        _________________________________
//        调用类的class属性
        System.out.println ( Student.class );
//        类的forName()静态方法
        try{
            Class<?> aClass = Class.forName ( "com.gen.entity.Student" );
            System.out.println ( aClass );
        } catch(ClassNotFoundException e){
            e.printStackTrace ( );
        }
class com.gen.entity.Student
class com.gen.entity.Student
class com.gen.entity.Student
2.class类对象获得信息
package com.gen.test;

import com.gen.entity.Student;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestRefelect {
    public static void main(String[] args) throws InvocationTargetException{
//        demo02 ();
//        demo03 ();
//        demo04 ();
//        demo05 ();
//        demo06 ();
//        demo07 ();
//        demo08 ( );
        demo09 ();
    }



    static void demo01( ){
        //    调用对象的getClass()方法
        Student student = new Student ( );
        System.out.println ( student.getClass ( ) );
//        _________________________________
//        调用类的class属性
        System.out.println ( Student.class );
//        类的forName()静态方法
        try{
            Class<?> aClass = Class.forName ( "com.gen.entity.Student" );
            System.out.println ( aClass );
        } catch(ClassNotFoundException e){
            e.printStackTrace ( );
        }
    }

    //    获得方法
    public static void demo02( ){
        try{
            Class<?> aClass = Class.forName ( "com.gen.entity.Student" );
//        获取所有的公共方法 本类、父类、接口类的所有方法
            Method[] methods = aClass.getMethods ( );
            for(Method method : methods){
                System.out.println ( method );
            }
//            只要当前类的
            System.out.println ( "==================" );
            Method[] declaredMethods = aClass.getDeclaredMethods ( );
            for(Method declar : declaredMethods){
                System.out.println ( declar );
            }
        } catch(ClassNotFoundException e){
            e.printStackTrace ( );
        }
    }

    //    获取所有的接口方法
    static void demo03( ){
        try{
            Class<?> aClass = Class.forName ( "com.gen.entity.Student" );
            Class<?>[] interfaces = aClass.getInterfaces ( );
            for(Class<?> inter : interfaces){
                System.out.println ( inter );
            }
        } catch(ClassNotFoundException e){
            e.printStackTrace ( );
        }
    }

    //    获取所有的父类,object
    static void demo04( ){
        try{
            Class<?> aClass = Class.forName ( "com.gen.entity.Student" );
            Class<?> superclass = aClass.getSuperclass ( );
            System.out.println ( superclass );
        } catch(ClassNotFoundException e){
            e.printStackTrace ( );
        }
    }

    //    获得所有的构造方法
    static void demo05( ){
        try{
            Class<?> aClass = Class.forName ( "com.gen.entity.Student" );
            Constructor<?>[] constructors = aClass.getConstructors ( );
            for(Constructor<?> constructor : constructors){
                System.out.println ( constructor );
            }
        } catch(ClassNotFoundException e){
            e.printStackTrace ( );
        }
    }

    //    获取所有的属性
    static void demo06( ){
        try{
            Class<?> aClass = Class.forName ( "com.gen.entity.Student" );
            Field[] fields = aClass.getFields ( );
            for(Field field : fields){
                System.out.println ( field );
            }
        } catch(ClassNotFoundException e){
            e.printStackTrace ( );
        }
    }

    //    反射代表的实例
    static void demo07( ){
        try{
            Class<?> aClass = Class.forName ( "com.gen.entity.Student" );
            Object o = null;
            try{
                o = aClass.newInstance ( );
                Student student = (Student) o;
                student.IMethod ( );
            } catch(InstantiationException e){
                e.printStackTrace ( );
            } catch(IllegalAccessException e){
                e.printStackTrace ( );
            }

        } catch(ClassNotFoundException e){
            e.printStackTrace ( );
        }
    }

    //    操作属性
    static void demo08( ) throws InvocationTargetException{
        try{
            Class<?> aClass = Class.forName ( "com.gen.entity.Student" );
            try{
                Student student = (Student) aClass.newInstance ( );

                try{
                   Field nameField = aClass.getDeclaredField ( "name" );
//                    开启访问权限
                    nameField.setAccessible ( true );
                    nameField.set ( student, "zhangsan" );
                    System.out.println ( student );
                } catch(NoSuchFieldException e){
                    e.printStackTrace ( );
                }
                System.out.println ("================" );
//                調取私有方法
                try{
                    Method myMethod = aClass.getDeclaredMethod ( "myMethod",null );
                    myMethod.setAccessible ( true );
                    myMethod.invoke ( student,null );
                } catch(NoSuchMethodException e){
                    e.printStackTrace ( );
                }

            } catch(InstantiationException e){
                e.printStackTrace ( );
            } catch(IllegalAccessException e){
                e.printStackTrace ( );
            }
        } catch(ClassNotFoundException e){
            e.printStackTrace ( );
        }
    }
//    调用私有带参数方法
    static void demo09(){
        try{
            Class<?> aClass = Class.forName ( "com.gen.entity.Student" );
            try{
                Method sayName = aClass.getDeclaredMethod ( "sayName", String.class );
                sayName.setAccessible ( true );
                try{
                    Student student = (Student)aClass.newInstance ( );
                    sayName.invoke ( student, "zhangsan" );
                } catch(IllegalAccessException e){
                    e.printStackTrace ( );
                } catch(InvocationTargetException e){
                    e.printStackTrace ( );
                } catch(InstantiationException e){
                    e.printStackTrace ( );
                }
            } catch(NoSuchMethodException e){
                e.printStackTrace ( );
            }

        } catch(ClassNotFoundException e){
            e.printStackTrace ( );
        }
    }
}

3.动态加载类名和方法名
             e.printStackTrace ( );
            }
            System.out.println ("================" );

// 調取私有方法
try{
Method myMethod = aClass.getDeclaredMethod ( “myMethod”,null );
myMethod.setAccessible ( true );
myMethod.invoke ( student,null );
} catch(NoSuchMethodException e){
e.printStackTrace ( );
}

        } catch(InstantiationException e){
            e.printStackTrace ( );
        } catch(IllegalAccessException e){
            e.printStackTrace ( );
        }
    } catch(ClassNotFoundException e){
        e.printStackTrace ( );
    }
}

// 调用私有带参数方法
static void demo09(){
try{
Class<?> aClass = Class.forName ( “com.gen.entity.Student” );
try{
Method sayName = aClass.getDeclaredMethod ( “sayName”, String.class );
sayName.setAccessible ( true );
try{
Student student = (Student)aClass.newInstance ( );
sayName.invoke ( student, “zhangsan” );
} catch(IllegalAccessException e){
e.printStackTrace ( );
} catch(InvocationTargetException e){
e.printStackTrace ( );
} catch(InstantiationException e){
e.printStackTrace ( );
}
} catch(NoSuchMethodException e){
e.printStackTrace ( );
}

    } catch(ClassNotFoundException e){
        e.printStackTrace ( );
    }
}

}


#### 3.动态加载类名和方法名

https://blog.csdn.net/weixin_55768452/article/details/115270228
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值