多线程学习
进程可能包含多个线程,都会有 main 线程和 gc 线程。
// 继承 **Thread** 类,重写 **run()** 方法,创建线程对象,调用 start() 开启线程
// TestThread1 extends Thread
TestThread1 t1 = new TestThread1();
t1.start();
// 实现 **Runnable** 接口,重写 **run()** 方法,创建接口的实现类对象,创建 Thread 调用 start() 启动线程
// 方便同一个对象被多个线程使用,避免单继承的局限性
// TestThread2 implements Runnable
TestThread2 t2 = new TestThread2();
new Thread(t2).start();
// 实现 **Callable ** 接口
package com.wang.ThreadDemo;
import java.util.concurrent.*;
public class TestCallable implements Callable {
@Override
public Object call() throws Exception {
return "Hello World!";
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestCallable t1 = new TestCallable();
TestCallable t2 = new TestCallable();
// 创建执行服务
ExecutorService ser = Executors.newFixedThreadPool(3);
// 提交执行
// ser.execute(Runnable command) 执行命令,无返回值
Future submit1 = ser.submit(t1);
Future submit2 = ser.submit(t2);
// 获取结果
String res1 = (String)submit1.get();
String res2 = (String)submit2.get();
// 关闭服务
ser.shutdownNow();
}
}
静态代理模式
线程底部是 静态代理模式
// 真实对象 和 代理对象 实现同一个接口
// 代理对象 代理 真实角色
// 好处:代理对象可以做很多事情,真实对象专注做自己的事情
lamda表达式
函数式接口:任何接口,如果只包含唯一一个抽象方法,就是函数式接口
对于函数式接口,可通过lamda表达式来创建该接口的对象
public class TestLamda {
// 3.静态内部类
static class Tface2 implements Itface{
@Override
public void lamda() {
System.out.println("i like lamda2!");
}
}
public static void main(String[] args) {
Itface tface = new Tface1();
tface.lamda();
tface = new Tface2();
tface.lamda();
// 4.局部内部类
class Tface3 implements Itface{
@Override
public void lamda() {
System.out.println("i like lamda3!");
}
}
tface = new Tface3();
tface.lamda();
// 5.匿名内部类,必须借助接口或者父类
tface = new Itface() {
@Override
public void lamda() {
System.out.println("i like lamda4!");
}
};
tface.lamda();
// 6.lamda表达式
tface = () -> {
System.out.println("i like lamda5!");
};
tface.lamda();
}
}
// 1.定义一个函数式接口
interface Itface{
void lamda();
}
// 2.外部实现类
class Tface1 implements Itface{
@Override
public void lamda() {
System.out.println("i like lamda1!");
}
}
去掉类名,去掉方法名,去掉参数类型,只有一个参数简化括号,只有单行代码简化花括号
上述变成:tface = () -> System.out.println("i like lamda5!");
线程状态
新生状态(new),就绪状态(start),运行状态,死亡状态, 阻塞状态(sleep,wait)
每个对象都有一把锁,sleep不会释放锁,抱着锁睡觉
线程礼让 yield,礼让不一定成功 Thread.yield();
合并线程 Join,thread.join(); 调用插队线程的join方法。
getState() 获取线程状态,getPriority() 获取线程优先级,优先级从1-10
线程分为用户线程和守护线程,setDaemon 设置守护线程
线程同步
车站买票、银行取钱、ArrayList() 等都是典型的线程不同步问题。
synchronized 控制对对象的访问,每个对象对应一把锁,可以锁 代码块 和 方法
synchronized (obj) {},obj称为同步监视器,推荐使用共享资源作为同步监视器
package com.wang.ThreadDemo;
import java.util.ArrayList;
import java.util.List;
public class ThreadSynchronized {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// 不加锁
// for (int i = 0; i < 50000; i++) {
// new Thread(() -> {
// list.add(Thread.currentThread().getName());
// }).start();
// }
// 给list加锁
for (int i = 0; i < 50000; i++) {
new Thread(() -> {
synchronized (list) {
list.add(Thread.currentThread().getName());
}
}).start();
}
// 休眠,主线程等待其他线程运行完
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list.size());
}
}
某一个同步块同时拥有两个以上对象的锁,相互等待对方释放资源,造成死锁现象。 持有且等待
产生死锁的四个必要条件:
互斥条件、请求与保持条件、不剥夺条件、循环等待条件
Lock() 显式定义同步锁 :ReentrantLock 可重入锁
class A {
private final ReentrantLock lock = new ReentrantLock();
public void m() {
lock.lock();
try {
// 保证线程安全的代码
} finally{
lock.unlock();
}
}
}
生产者消费者问题
管程法:利用缓冲区解决生产者消费者问题,实现生产者和消费者之间的通信
信号灯法:并发协作模型 “生产者 / 消费者模式” ,通过标志位方式来等待(wait)和唤醒(notify)
注解
Annotation Type 常见注解:@Override、@Deprecated、@SuppressWarnings("all")
元注解meta-annotation:@Target、@Retention(SOURCE < CLASS < RUNTIME)@Documented、@Inherited
package com.wang;
import java.lang.annotation.*;
public class TestAnno {
@MyAnnotation(name = "wang", id = 3)
public void test() {
}
}
// 表示注解可以用在哪些地方
@Target(value = {ElementType.METHOD,ElementType.TYPE})
// 表示注解在什么地方有效 RUNTIME > CLASS > SOURCE
@Retention(value = RetentionPolicy.RUNTIME)
// 表示注解是否生成在JavaDoc中
@Documented
// 表示是否继承父类
@Inherited
@interface MyAnnotation{
// 注解的参数:参数类型 + 参数名 ();
String name() default "";
int id() default -1;
}
反射
一个类在内存中只有一个Class对象
一个类被加载后,类的整个结构都会被封装在Class对象中
package com.wang;
public class Reflection_ {
public static void main(String[] args) throws ClassNotFoundException {
// 1.通过类名.class获得
System.out.println(Student.class);
// 2.通过对象获得
Person p = new Student("小明");
System.out.println(p.getClass());
// 3.通过Class的静态方法forName获得
System.out.println(Class.forName("com.wang.Student"));
// 4.基本内置类型的包装类有一个Type属性
System.out.println(Integer.TYPE);
System.out.println(p.getClass().getSuperclass());
}
}
class Person{
String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student(String name) {
this.name = name;
}
}
class Teacher extends Person{
public Teacher(String name) {
this.name = name;
}
}
System.out.println(Object.class); // class java.lang.Object
System.out.println(Comparable.class); // interface java.lang.Comparable
System.out.println(String[].class); // class [Ljava.lang.String;
System.out.println(int[][].class); // class [[I
System.out.println(Override.class); // interface java.lang.Override
System.out.println(ElementType.class); // class java.lang.annotation.ElementType
System.out.println(Integer.class); // class java.lang.Integer
System.out.println(void.class); // void
System.out.println(Class.class); // class java.lang.Class
类加载
加载到内存,产生一个类对应的Class对象
链接,链接结束后,为类变量分配内存,静态变量完成默认初始化,常量存入常量池
初始化,执行<clinit>(),按顺序执行静态初始化和静态代码块
不会产生类的引用的方法:
子类调用父类的静态变量或静态方法,不会导致子类初始化
数组定义类引用,不会触发此类的初始化
引用常量不会触发此类的初始化
// 系统类加载器->扩展类加载器->根加载器(引导类加载器)
// 获取系统类加载器可以加载的路径
System.getProperty("java.class.path");
反射获取类信息
// getFields 获取本类public的属性
// getDeclaredFields 获取本类所有的属性
// getMethods 获取本类及父类所有public的方法 *
// getDeclaredMethods 获取本类的所有方法
// getConstructors() 获取本类public构造方法
// getDeclaredConstructors() 获取本类所有构造方法
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Ref {
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("com.wang.Person");
// 类必须存在无参构造器
Person p1 = (Person) c1.newInstance();
System.out.println(p1);
// 通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class);
Person p2 = (Person)constructor.newInstance("wang");
System.out.println(p2);
// 反射调用方法
Method run = c1.getDeclaredMethod("run", String.class, int.class);
run.setAccessible(true); // 爆破
run.invoke(p2, "wang", 3);
// 改变私有属性
Field age = c1.getDeclaredField("age");
age.setAccessible(true);
age.set(p1, 12);
System.out.println(p1.getAge());
}
}
反射获取泛型
public void test01(Map<String,Person> map) {
}
public Map<String, Person> test02(){
System.out.println("test02");
return null;
}
public static void main(String[] args) throws Exception {
Method method = Ref.class.getMethod("test01", Map.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println(genericParameterType);
if (genericParameterType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
Method method1 = Ref.class.getMethod("test02", null);
Type genericReturnType = method1.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
getAnnotation 获取注解 ** 还会回来看的
浙公网安备 33010602011771号