- 1.Java程序在运行得时候默认就会产生一个进程
- 2.这个进程会有一个主线程
- 3.代码都在主线程中执行
线程的生命周期
线程的执行方式
public class Java02_Thread {
public static void main(String[] args) throws Exception {
// TODO 线程 - 执行方式(串行,并发)
// 串行执行:多个线程连接成串,然后按照顺序执行
// 并发执行:多个线程是独立,谁抢到了CPU得执行权,谁就能执行
MyThread1 t1 = new MyThread1();
MyThread2 t2 = new MyThread2();
t1.start();
t2.start();
// 将线程连接成串
t1.join();
t2.join(); //t1-t2
System.out.println("main线程执行完毕");
}
}
// TODO 第一个线程
class MyThread1 extends Thread {
// 重写运行指令
public void run() {
System.out.println("MyThread-1 : " + Thread.currentThread().getName());
}
}
// TODO 第二个线程
class MyThread2 extends Thread {
// 重写运行指令
public void run() {
System.out.println("MyThread-2 : " + Thread.currentThread().getName());
}
}
自定义线程
public class Java04_Thread_Run {
public static void main(String[] args) throws Exception {
// TODO 线程 - 运行
MyThread3 t3 = new MyThread3();
t3.start();
MyThread4 t4 = new MyThread4();
t4.start();
MyThread5 t5 = new MyThread5("t5");
MyThread5 t55 = new MyThread5("t55");
t5.start();
t55.start();
System.out.println("main线程执行");
}
}
// TODo 自定义线程
// 1. 继承线程类(父类)
// 2. 重写run方法
class MyThread3 extends Thread {
@Override
public void run() {
System.out.println("t3 线程执行");
}
}
class MyThread4 extends Thread {
@Override
public void run() {
System.out.println("t4 线程执行");
}
}
class MyThread5 extends Thread {
private String threadName;
public MyThread5(String name) {
threadName = name;
}
@Override
public void run() {
System.out.println(threadName + " 线程执行");
}
}
// TODO 构建线程对象时,可以只把逻辑传递给这个对象
// 传递逻辑时,需要遵循规则:() -> { 逻辑 }
Thread t6 = new Thread(() -> {
System.out.println("线程执行1");
});
t6.start();
// TODO 构建线程对象时,可以传递实现了Runnable接口得类得对象,一般使用匿名类
Thread t8 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程执行");
}
});
t8.start();
线程池
所谓得线程池,其实就是线程对象得容器
可以根据需要,在启动时,创建一个或者多个线程对象
// Java种有4种比较常见得线程池
// 1. 创建固定数量得线程对象
// ExecutorService是线程服务对象
//ExecutorService executorService = Executors.newFixedThreadPool(3);
// 2. 根据需求动态创建线程
//ExecutorService executorService = Executors.newCachedThreadPool();
// 3. 单一线程
//ExecutorService executorService = Executors.newSingleThreadExecutor();
// 4. 定时调度线程
ExecutorService executorService = Executors.newScheduledThreadPool(3);
for ( int i = 0; i < 5; i++ ) {
executorService.submit(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
线程同步
public class Java06_Thread_Syn {
public static void main(String[] args) throws Exception {
// synchronized - 同步关键字
// 多个线程访问同步方法时,只能一个一个访问,同步操作
// synchronized关键字还可以修饰代码块,称之为同步代码块
/*
synchronized( 用于同步得对象 ) {
处理逻辑
}
*/
Num num = new Num();
User user = new User(num);
user.start();
Bank bank = new Bank(num);
bank.start();
}
}
class Num {
}
class Bank extends Thread {
private Num num;
public Bank( Num num ) {
this.num = num;
}
public void run() {
synchronized (num) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("9:00, 开发,开始叫号");
num.notifyAll();
}
}
}
class User extends Thread {
// public synchronized void test() {
//
// }
private Num num;
public User( Num num ) {
this.num = num;
}
public void run() {
synchronized ( num ) {
System.out.println("我是号码1,银行还没开门,我需要等一会");
try {
num.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("叫到我得号了,该我办业务了。");
}
}
wait & sleep
-
- 名字
wait : 等待 sleep : 休眠
- 2.从属关系
wait : Object, 成员方法 sleep : Thread, 静态方法
-
- 使用方式
wait : 只能使用在同步代码中 sleep : 可以在任意地方法使用
-
- 阻塞时间
wait : 超时时间(会发生错误) sleep : 休眠时间(不会发生错误)
-
- 同步处理
wait : 如果执行wait方法,那么其他线程有机会执行当前的同步操作。 sleep : 如果执行sleep方法,那么其他线程没有机会执行当前的同步操作。
线程的安全问题
所谓的线程安全问题,其实就是多个线程在并发执行时,修改了共享内存中共享对象的属性,导致的数据冲突问题
public class Java07_Thread_Safe {
public static void main(String[] args) throws Exception {
User7 user = new User7();
Thread t1 = new Thread(()->{
user.name = "zhangsan";
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(user.name);
});
Thread t2 = new Thread(()->{
user.name = "lisi";
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(user.name);
});
t1.start();
t2.start();
System.out.println("main线程执行完毕");
}
}
class User7 {
public String name;
}
栈内存是独享的,堆内存是共享的。两个线程访问同一个对象时,若对对象的属性进行修改,会引起冲突。
反射
- 常用方法和操作
public class Java01_Reflect {
public static void main(String[] args) throws Exception {
// TODO 反射
// 多态
User user = new Child();
user.test1();
//user.test2();
// 类对象
Class<? extends User> aClass = user.getClass();
// TODO 获取类的名称
System.out.println(aClass.getName()); // 获取类的完整名称(包含包名)
System.out.println(aClass.getSimpleName()); // 获取类的名称
System.out.println(aClass.getPackageName()); // 获取类的包的名称
// TODO 获取类的父类
Class<?> superclass = aClass.getSuperclass();
System.out.println(superclass);
// TODO 获取类的接口
Class<?>[] interfaces = aClass.getInterfaces();
System.out.println(interfaces.length);
// TODO 获取类的属性
Field f = aClass.getField("xxxxx"); // public权限的属性
Field f1 = aClass.getDeclaredField("xxxxx"); // 所有权限
Field[] fields = aClass.getFields();// 所有public权限的属性
Field[] declaredFields = aClass.getDeclaredFields(); // 所有权限
// TODO 获取类的方法
Method method = aClass.getMethod("test2");// public
Method xxxx = aClass.getDeclaredMethod("xxxx"); // 所有权限
Method[] methods = aClass.getMethods();// public
Method[] declaredMethods = aClass.getDeclaredMethods(); // 所有权限
// TODO 构造方法
Constructor<? extends User> constructor = aClass.getConstructor();
Constructor<?>[] constructors = aClass.getConstructors();
aClass.getDeclaredConstructor();
// TODO 获取权限(修饰符) :多个修饰符会融合成一个int值
int modifiers = aClass.getModifiers();
boolean aPrivate = Modifier.isPrivate(modifiers);
}
}
class User {
public void test1() {
System.out.println("test1...");
}
}
class Child extends User {
public void test2() {
System.out.println("test2...");
}
}
- 类加载器
Java种的类主要分为3种: - Java核心类库种的类:String, Object
- JVM 软件平台开发商
- 自己写的类,User, Child
类加载器也有3种: -
- BootClassLoader : 启动类加载器(加载类时,采用操作系统平台语言实现)
-
- PlatformClassLoader :平台类加载器
-
- AppClassLoader : 应用类加载器
public class Java02_Reflect_ClassLoader {
public static void main(String[] args) throws Exception
// TODo 获取类的信息
Class<Student> studentClass = Student.class;
// 获取类的加载器对象
ClassLoader classLoader = studentClass.getClassLoader();
System.out.println(classLoader);
System.out.println(classLoader.getParent());
System.out.println(classLoader.getParent().getParent());
Class<String> stringClass = String.class;
// 获取类的加载器对象
ClassLoader classLoader1 = stringClass.getClassLoader();
System.out.println(classLoader1);
// 加载Java核心类库 > 平台类库 > 自己类
}
}
class Student {
}
使用反射实现登录功能
public class Java03_Reflect_Test {
public static void main(String[] args) throws Exception {
// TODO 反射 - 练习
// 员工的登录功能,
// 构造方法对象
Class empClass = Emp.class;
Constructor declaredConstructor = empClass.getDeclaredConstructor();
// 构建对象
Object emp = declaredConstructor.newInstance();
// 获取对象的属性
Field account = empClass.getField("account");
Field password = empClass.getField("password");
// 给属性赋值
account.set(emp, "admin");
password.set(emp, "admin");
// 获取登录方法
Method login = empClass.getMethod("login");
// 调用方法
Object result = login.invoke(emp);
System.out.println(result);
}
}
// 员工
class Emp {
public String account;
public String password;
public boolean login() {
if ( "admin".equals(account) && "admin".equals(password) ) {
return true;
} else {
return false;
}
}
}