p800 守护线程概述
p801 实现守护线程
package com.bjpowernode.java.thread;
public class ThreadTest14 {
public static void main(String[] args) {
BackDataThread bdt = new BackDataThread();
bdt.setName("备份数据的线程");
bdt.setDaemon(true);
bdt.start();
//主线程是用户线程
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+"----->"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//现在备份线程还不是守护线程。如果想要把备份线程设置为守护线程,很简单
//只需要在启动之前加一句
// bdt.setDaemon(true);即可
//设置之后,用户线程结束之后,守护线程自动结束。
//设置之后,用户线程结束之后,守护线程自动结束。
}
}
class BackDataThread extends Thread{
@Override
public void run() {
int i= 0;
//即使是死循环,但是作为守护线程,等到用户线程结束时,他也会自动结束
while(true){
System.out.println(Thread.currentThread().getName()+"------------>"+(++i));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
p802 定时器概述
p803 实现定时器
自定义类实现接口
package com.bjpowernode.java.thread;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class TimerTest {
public static void main(String[] args) throws ParseException {
//创建定时器对象
//Timer timer = new Timer(true);参数true表示以守护线程运行
Timer timer = new Timer();
//创建定时任务
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//设置第一次时间为2020年4月2日九点半
Date firstTime = sdf.parse("2021-04-02 09:30:00");
timer.schedule(new LogTimerTask(),firstTime,1000*10);
}
}
class LogTimerTask extends TimerTask{
/**
* The action to be performed by this timer task.
*/
@Override
public void run() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strTime = sdf.format(new Date());
System.out.println(strTime+":成功完成了一次数据备份!");
}
}
匿名内部类
import java.util.TimerTask;
public class TimerTest02 {
public static void main(String[] args) throws ParseException {
//创建定时器对象
//Timer timer = new Timer(true);参数true表示以守护线程运行
Timer timer = new Timer();
//创建定时任务
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//设置第一次时间为2020年4月2日九点半
Date firstTime = sdf.parse("2021-04-02 09:30:00");
timer.schedule(new TimerTask(){
/**
* The action to be performed by this timer task.
*/
@Override
public void run() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strTime = sdf.format(new Date());
System.out.println(strTime+":成功完成了一次数据备份!");
}
},firstTime,1000*10);
}
}
p804 实现线程的第三种方式
package com.bjpowernode.java.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/*
实现线程的第三种方式:callable(),可以得到线程的返回值。
*/
public class ThreadTest15 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//第一步:创建一个"未来任务类"对象
//参数很重要,需要实现一个Callable接口的实现类对象
FutureTask futureTask = new FutureTask(new Callable() {
@Override
public Object call() throws Exception {//call()方法相当于run()方法
//线程执行任务。可能会有一个执行结果。
//模拟执行
System.out.println("call method begin");
Thread.sleep(1000*10);
System.out.println("call method end");
int a = 100;
int b = 200;
return a+b;//return自动装箱后返回Integer类型
}
});
//创建线程对象
Thread t = new Thread(futureTask);//新建线程对象的时候将上面的未来任务传进来
t.setName("ttt");
t.start();
//在主线程如何获取t线程的返回结果
//get()方法的执行会导致当前线程阻塞,效率较低。但是他可以拿到返回结果。
Object obj = futureTask.get();
//但是现在有一个问题,main()方法想要执行必须等待get方法结束
//而get方法又要等待另一个线程执行结束。
//另一个线程执行需要时间
System.out.println("hello main");
}
}
p805 wait和notify方法(生产者和消费者)
p806 生产者和消费者模式
p807 生产者和消费者模式代码实现【生产1个,消费1个】
package com.bjpowernode.java.thread;
import java.util.ArrayList;
import java.util.List;
public class ThreadTest16 {
public static void main(String[] args) {
//创建一个仓库对象,共享的
List list = new ArrayList();
//创建两个线程对象
Thread t1 = new Thread(new Producer(list));
Thread t2 = new Thread(new Consumer(list));
//设置线程名字
t1.setName("t1");
t2.setName("t2");
//启动
t1.start();
t2.start();
}
}
class Producer implements Runnable{
private List list;
public Producer(List list) {
this.list = list;
}
@Override
public void run() {
while(true){
//给仓库对象list加锁
synchronized (list){
//如果list集合大于0,那么就等待,不需要生产了。
if (list.size() > 0){
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果if条件不成立,那就说明list集合为空,开始生产
Object obj = new Object();
list.add(obj);
System.out.println(Thread.currentThread().getName()+"---->"+obj);
//唤醒消费者进行消费
list.notifyAll();
}
}
}
}
class Consumer implements Runnable{
private List list;
public Consumer(List list) {
this.list = list;
}
@Override
public void run() {
while(true){
synchronized (list){
//如果list集合等关于0,那么就等待,不能继续消费。
if (list.size() == 0){
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果if条件不成立,那就说明list集合不为空,开始消费
Object obj = list.remove(0);//参数为数组中的元素下标。
System.out.println(Thread.currentThread().getName()+"---->"+obj);
//唤醒生产者开始生产
list.notifyAll();
}
}
}
}
p808 生产者和消费者模式代码理解【平衡】![在这里插入图片描述](https://img-blog.csdnimg.cn/20210405205013124.png)
p809 布置线程作业
package com.bjpowernode.java.homework;
/*
运行不成功,下次找答案再试试
*/
import java.util.ArrayList;
import java.util.List;
public class ThreadNumber {
public static void main(String[] args) {
//创建一个仓库对象,共享的
Integer num = 0;
//创建两个线程对象
Thread t1 = new Thread(new Number(num));
Thread t2 = new Thread(new Number(num));
//设置线程名字
t1.setName("t1");
t2.setName("t2");
//启动
t1.start();
t2.start();
}
}
class Number implements Runnable{
private Integer num;
public Number(int num) {
this.num = num;
}
@Override
public void run() {
while(true){
synchronized (num){
//如果是偶数,那就等待
if (num % 2 == 0){
try {
num.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果是奇数,那就输出
System.out.println(Thread.currentThread().getName()+"--->"+num);
num++;
num.notifyAll();
}
synchronized (num){
//如果是奇数,那就等待
if (num % 2 != 0){
try {
num.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//如果是偶数,那就输出
System.out.println(Thread.currentThread().getName()+"--->"+num);
num++;
num.notifyAll();
}
}
}
}
p810 反射机制
p811 反射机制可以草操作字节码文件【获取字节码的第一种方式】
package com.bjpowernode.java.reflect;
/*
反射机制可以操作字节码文件,但是怎么拿到字节码文件?
如何拿到字节码文件?
*/
public class ReflectTest01 {
public static void main(String[] args) {
try {
Class c1 = Class.forName("java.lang.String");
Class c2 = Class.forName("java.util.Dtae");
Class c3 = Class.forName("java.lang.Integer");
Class c4 = Class.forName("java.lang.System");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
p812 获取字节码的第二种方式
p813 获取字节码的第三种方式
package com.bjpowernode.java.reflect;
import java.util.Date;
/*
反射机制可以操作字节码文件,但是怎么拿到字节码文件?
如何拿到字节码文件?
*/
public class ReflectTest01 {
public static void main(String[] args) {
Class c1 = null;
Class c2 = null;
try {
c1 = Class.forName("java.lang.String");
c2 = Class.forName("java.util.Date");
Class c3 = Class.forName("java.lang.Integer");
Class c4 = Class.forName("java.lang.System");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//java中任何一个对象都有一个方法::getClass()
String s = "abc";
Class x = s.getClass();
System.out.println(x);//class java.lang.String.x表示String类型。x表示String.class字节码文件
System.out.println(c1 == x);//双等号判断内存地址,c1和x都表示String.class字节码文件
Date time = new Date();
Class y = time.getClass();
System.out.println(y);
System.out.println(c2 == y);//true.c2和y在方法区都指向Date.class字节码文件。
//java中任何一种类型,包括基本数据类型给,都有.class属性
Class z = String.class;
Class k = Date.class;
Class f = int.class;
Class e = double.class;
System.out.println(x == z);
}
}
p814 通过反射机制实例化对象
package com.bjpowernode.java.reflect;
import com.bjpowernode.java.bean.User;
public class ReflectTest02 {
public static void main(String[] args) {
//第一种方法创建对象,实例化对象。
User user = new User();
System.out.println(user);
//第二种方法创建对象
try {
Class c = Class.forName("com.bjpowernode.java.bean.User");
Object o = c.newInstance();
System.out.println(o);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
p815 通过读属性文件实例化对象
测试文件
package com.bjpowernode.java.reflect;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Properties;
/*
验证反射机制创建对象的灵活性
*/
public class ReflectTest03 {
public static void main(String[] args) throws Exception {
//通过I/O流读取配置文件
FileReader reader = new FileReader("Chapter25_Reflect/classinfo.properties");
//创建属性类对象pro
Properties pro = new Properties();
//加载
pro.load(reader);
//关闭流
reader.close();
//通过key获取value
String className = pro.getProperty("className");
//拿到类名
//System.out.println(className);
//通过反射机制创建对象
Class c = Class.forName(className);
Object obj = c.newInstance();
System.out.println(obj);
}
}
配置文件
#className=com.bjpowernode.java.bean.User
className=java.util.Timer
p816 只让静态代码块执行可以使用forName
package com.bjpowernode.java.reflect;
/*如果只希望一个类的静态代码块执行,其他代码一律不执行,那么就使用:
Class.forName("完整类名")
这个方法的执行会导致类加载,类加载时,静态代码块执行。
*/
public class ReflectTest04 {
public static void main(String[] args) {
// Myclass mc = new Myclass();
try {
Class.forName("com.bjpowernode.java.reflect.Myclass");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
p817 获取类路径下文件的绝对路径
package com.bjpowernode.java.reflect;
import java.io.FileNotFoundException;
import java.io.FileReader;
public class AbsolutePath {
public static void main(String[] args) throws Exception {
//这种方式的路径缺点是:移植性差,在IDEA中默认的当前路径是project的根
//这个代码离开IDEA之后,换到其他位置,这个路径就无效了
// FileReader reader = new FileReader("Chapter25_Reflect");
//通用路径,这样编写,即使代码换位置之后,也能找到。
//前提是必须在类路径下
//什么是类路径?凡是在src下的都是类路径【记住】
//src是类路径的根路径
//当前线程对象【Thread.currentThread()】的类加载器对象【getContextClassLoader】的资源【getResource()】的路径
String path = Thread.currentThread().getContextClassLoader()
.getResource("classinfo2.properties").getPath();
//获取一个文件的绝对路径
System.out.println(path);
String path2 = Thread.currentThread().getContextClassLoader()
.getResource("com/bjpowernode/java/bean/db.properties").getPath();
//获取一个文件的绝对路径
System.out.println(path2);
}
}
p818 以流的形式直接返回
package com.bjpowernode.java.reflect;
import java.io.FileReader;
import java.nio.file.Path;
import java.util.Properties;
public class IoPropertiesTest {
public static void main(String[] args) throws Exception {
//获取绝对路径【通用方式】
String path = Thread.currentThread().getContextClassLoader()
.getResource("classinfo2.properties").getPath();
//System.out.println(path);
FileReader reader = new FileReader(path);
Properties pro = new Properties();
pro.load(reader);
reader.close();
//通过Key获取value
String className = pro.getProperty("className");
System.out.println(className);
}
}
package com.bjpowernode.java.reflect;
import java.io.FileReader;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.Properties;
public class IoPropertiesTest {
public static void main(String[] args) throws Exception {
//获取绝对路径【通用方式】
//
// String path = Thread.currentThread().getContextClassLoader()
// .getResource("classinfo2.properties").getPath();
//
//
// //System.out.println(path);
// FileReader reader = new FileReader(path);
//直接以流的形式返回
InputStream reader = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("classinfo2,properties");
Properties pro = new Properties();
pro.load(reader);
reader.close();
//通过Key获取value
String className = pro.getProperty("className");
System.out.println(className);
}
}
p819 资源绑定器
java.util包下提供了一个资源绑定器,便于获取属性配置文件下中的内容
资源绑定器只能绑定xxx.properties配置文件,并且这个文件必须在类路径下,文件扩展名也必须是properties
并且在写路径的时候,路径后面的扩展名不能写。
package com.bjpowernode.java.reflect;
import java.util.ResourceBundle;
public class ResourceBundleTest {
public static void main(String[] args) {
//注意都是以src作为起点。
ResourceBundle bundle = ResourceBundle.getBundle("classinfo2");
String className = bundle.getString("className");
System.out.println(className);
//都是以src下作为起点
ResourceBundle bundle2 = ResourceBundle.getBundle("com/bjpowernode/java/bean/db");
String className2 = bundle2.getString("className");
System.out.println(className2);
}
}
p820 类加载器概述【扩展】
p821 双亲委派机制【扩展】