超牛牪犇Java之线程的等待与唤醒&反射

本文详细介绍了一种利用三个线程交替打印线程名称的技术方案,并深入探讨了使用 Java 的 wait 和 notify 方法以及 Lock 接口和 Condition 对象实现线程间的同步控制。此外,还全面介绍了 Java 中反射的基本原理及其应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.线程的等待与唤醒

例题:

利用三个线程间隔打印现成的名字 一共打印15次

1.用wait和notify或者notifyAll

写一个锁类 顺便写出计数的变量 和 标识

class MyLock{
	private MyLock() {		
	}
	public static final MyLock MY_LOCK = new MyLock();
	public static int flag = 1;
	public static int num = 0;
}

用来创建第一个线程的实现类

并且 为了让线程每次唤醒都重新判断标记 这里用while而不是if

class Print1Runnable implements Runnable{
	@Override
	public void run() {
		while (true) {
			synchronized (MyLock.MY_LOCK) {
				if (MyLock.num == 150) {
					break;
				}
				MyLock.num++;
				while(MyLock.flag != 1) {
					try {
						MyLock.MY_LOCK.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				System.out.println(Thread.currentThread().getName());
				
				MyLock.flag = 2;
				//一个线程打印完 唤醒另外两个线程
				MyLock.MY_LOCK.notifyAll();
			}
		}
	}
}

用来创建第二个线程的实现类

class Print2Runnable implements Runnable{
	@Override
	public void run() {
		while (true) {
			synchronized (MyLock.MY_LOCK) {
				if (MyLock.num == 150) {
					break;
				}
				MyLock.num++;
				while (MyLock.flag != 2) {
					try {
						MyLock.MY_LOCK.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				System.out.println(Thread.currentThread().getName());
				
				MyLock.flag = 3;
				MyLock.MY_LOCK.notifyAll();
			}
		}
	}
}

用来创建第三个线程的实现类

class Print3Runnable implements Runnable{
	@Override
	public void run() {
		while (true) {
			synchronized (MyLock.MY_LOCK) {
				if (MyLock.num == 150) {
					break;
				}
				MyLock.num++;
				while (MyLock.flag != 3) {
					try {
						MyLock.MY_LOCK.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				System.out.println(Thread.currentThread().getName());
				MyLock.flag = 1;
				MyLock.MY_LOCK.notifyAll();
			}
		}
	}
}

创建线程:

public static void main(String[] args) {
	Print1Runnable p1 = new Print1Runnable();
	Thread t1 = new Thread(p1);
	Print2Runnable p2 = new Print2Runnable();
	Thread t2 = new Thread(p2);
	Print3Runnable p3 = new Print3Runnable();
	Thread t3 = new Thread(p3);
	t1.start();
	t2.start();
	t3.start();
}

2.用Lock锁完成

Condition对象 可以精准的控制哪一个线程等待或唤醒

newCondition方法

await方法

signal方法

创建锁类 并创建Condition对象 

class LockX{
	private LockX() {
		// TODO Auto-generated constructor stub
	}
	public static final ReentrantLock LOCK_X = new ReentrantLock();
	//创建Condition对象
	public static final Condition c1 = LOCK_X.newCondition();
	public static final Condition c2 = LOCK_X.newCondition();
	public static final Condition c3 = LOCK_X.newCondition();
	//创建计数器
	public static int num = 0;
	public static int flag = 1;
}

用来创建第一个线程的实现类

class P1Runnable implements Runnable{
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			LockX.LOCK_X.lock();
			try {
				if (LockX.num == 150) {
					break;
				}
				LockX.num++;
				if (LockX.flag != 1) {
					//让当前线程等待
					try {
						LockX.c1.await();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				System.out.println(Thread.currentThread().getName());
				LockX.flag = 2;
				LockX.c2.signal();
			} finally {
				// TODO: handle finally clause
				LockX.LOCK_X.unlock();
			}
		}
	}	
}

用来创建第二个线程的实现类

class P2Runnable implements Runnable{
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			LockX.LOCK_X.lock();
			try {
				if (LockX.num == 150) {
					break;
				}
				LockX.num++;
				if (LockX.flag != 2) {
					//让当前线程等待
					try {
						LockX.c2.await();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				System.out.println(Thread.currentThread().getName());
				LockX.flag = 3;
				LockX.c3.signal();
			} finally {
				// TODO: handle finally clause
				LockX.LOCK_X.unlock();
			}
		}
	}
}

用来创建第三个线程的实现类

class P3Runnable implements Runnable{
	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (true) {
			LockX.LOCK_X.lock();
			try {
				if (LockX.num == 150) {
					break;
				}
				LockX.num++;
				if (LockX.flag != 3) {
					//让当前线程等待
					try {
						LockX.c3.await();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				System.out.println(Thread.currentThread().getName());
				LockX.flag = 1;
				LockX.c1.signal();
			} finally {
				// TODO: handle finally clause
				LockX.LOCK_X.unlock();
			}
		}
	}	
}

创建线程:

public static void main(String[] args) {
	P1Runnable r1 = new P1Runnable();
	Thread t1 = new Thread(r1);
	P2Runnable r2 = new P2Runnable();
	Thread t2 = new Thread(r2);
	P3Runnable r3 = new P3Runnable();
	Thread t3 = new Thread(r3);
	t1.start();
	t2.start();
	t3.start();
}

二.反射

一.  先要知道类是如何被加载的,可以分为三个过程

1.加载(把.class文件 加载到内存中)

        把编译的.class文件 加载到方法区

        在堆区创建了一个表示该Class文件的对象

2.连接

        验证  查看一下你这个类的内部结构(成员变量 成员方法)

        准备  为静态成员变量开辟内存空间 并且赋初始值

        解析  把方法中的局部变量进行替换  如:a = 1 ;

               是直接把这个局部变量的位置替换成1

3.初始化

咱们new一个对象 进行初始化(堆开空间 和之前一样)

二.  那么类什么时候会被加载?

简单来说: 类被使用的时候就会被加载

当使用子类的对象时父类会先被加载

三.  类是是用什么被加载的?

类是用类加载器被加载的

1. 根加载器 加载java的核心类库

2. 扩展加载器 加载ext路径下的一些类

3. 系统加载器 加载咱们放进去的第三方类库

反射

反射可以把一个正在运行的类(已经加载到内存中的类)

通过Class文件的对象 直接获取该文件中的成员变量和方法(私有权限的也能访问)

那么, 如何通过反射获取Class文件对象呢?

1.对象获取

2.类名获取

3.常用静态方法获取

Person p = new Person();
//对象获取
Class<? extends Person> c1 = p.getClass();
System.out.println(c1);
//类名获取
Class<?> c2 = Person.class;
System.out.println(c2);
System.out.println(c1 == c2);
//静态方法获取
//注意 使用类的全限定类名(包名+类名)
Class<?> c3 = Class.forName("com.Commander.reflect.Person");
System.out.println(c3);
//利用文件对象 直接获取类中的构造方法
Class<?> c = Class.forName("com.Commander.reflect.Person");
//获取构造方法的数组(只能获取public公有的构造方法 私有化的获取不到)
Constructor<?>[] constructors = c.getConstructors();
//遍历
for (Constructor<?> constructor : constructors) {
	System.out.println(constructor);
}
//获取单个的构造方法
//参数是传入 可变参(...) 不传也行 
//不传相当于获取的是无参的构造方法
 Constructor<?> constructor = c.getConstructor();
System.out.println(constructor);
//参数是文件的对象
Constructor<?> constructor2 = c.getConstructor(String.class,int.class);
System.out.println(constructor2);
//用这个构造方法 来创建对象
//可以通过向下转型调用类中的特有方法
Object object = constructor.newInstance();
System.out.println(object);
//有参构造方法创建对象
Object object2 = constructor2.newInstance("taylor",30);
System.out.println(object2);

直接利用文件对象 快速创建对象

前提:

1.构造方法必须是public修饰

2.类必须是public修饰

3.必须提供无参的构造方法

Class<?> c = Class.forName("com.Commander.reflect.Person");
Object object = c.newInstance();
System.out.println(object);

获取私有的构造方法 需要打开访问权限

Class<?> c = Class.forName("com.Commander.reflect.Person");
//获取私有的构造方法
//IllegalAccessException 没有访问该方法的权限
Constructor<?> declaredConstructor = c.getDeclaredConstructor(String.class,int.class);
//打开访问权限
declaredConstructor.setAccessible(true);
Object newInstance = declaredConstructor.newInstance("swift",10);
System.out.println(newInstance);

获取成员变量并赋值

Class<?> c = Class.forName("com.Commander.reflect.Person");
//获取所有公开的成员变量
Field[] fields = c.getFields();
for (Field field : fields) {
	System.out.println(field);
}
//获取单个成员变量(传入成员变量的名字)
Field field = c.getField("name");
//创建一个对象 
Object object = c.newInstance();
//可以为对象中的这个成员变量赋值
field.set(object, "PC");
System.out.println(object);
Field field2 = c.getDeclaredField("age");
//打开权限
field2.setAccessible(true);
field2.set(object, 10);
System.out.println(object);
Class<?> c = Class.forName("com.Commander.reflect.Person");
//获取成员方法
Object object = c.newInstance();
Method method2 = c.getMethod("eat");
System.out.println(method2);
//调用成员方法
//参数一表示用哪个对象调用该方法
//参数二表示方法传入的参数
//该方法的返回值 就是你所调用的成员方法产生的返回值
Object invoke = method2.invoke(object);
System.out.println("我是方法的返回值" + invoke);
Method method3 = c.getMethod("speak",String.class);
Object invoke1 = method3.invoke(object,"hahaha");
Method declaredMethod = c.getDeclaredMethod("playGame",String.class);
declaredMethod.setAccessible(true);
declaredMethod.invoke(object, "WarFrame");
//获得所有公开的方法()包括继承的
Method[] methods = c.getMethods();
for (Method method : methods) {
	System.out.println(method);
}

利用反射向ArrayList<String>中添加Integeer数据

tips:编译成.Class文件后 代码中不存在泛型

ArrayList<String> list = new ArrayList<>();
Class<?> class1 = list.getClass();
Method method = class1.getMethod("add", Object.class);
System.out.println(method);
Object invoke = method.invoke(list, 123);
method.invoke(list, 456);
method.invoke(list, 789);
method.invoke(list, new Person());	
for (Object object : list) {
	System.out.println(object);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值