Java学习笔记 第九章 多线程和反射

JAVA学习笔记第九章

9.多线程和反射

image-20210609173953352

image-20210609174359909

image-20210609174444082

image-20210609174529498

9.1线程

9.1.1创建线程

image-20210609174911232

【2】创建线程:线程类——>线程对象

方式一:继承Thread类

image-20210609175500155

image-20210609175905423

原理图:

image-20210609180022458

运行结果:

image-20210609180050064

设置线程的名字:

image-20210609215752339

image-20210609220004419

方式一:通过setName设置

image-20210609215914786

image-20210609215813994

方式二:通过构造器和super设置,实际上还是调用父类的有参构造器

image-20210609220114177

例子:买车票

public class BuyTicketThread extends Thread {
    public BuyTicketThread(String name){
        super(name);
    }
    //一共10张票
    static int ticketNum = 10; //多个对象共享10张票

    //每个窗口都是一个线程对象:每个对象执行的代码放入run方法中
    @Override
    public void run() {
        //每个窗口后有100个人抢票
        for(int i = 1; i < 100; i++){
            //对票数进行判断
            if(ticketNum > 0) {
                System.out.println(this.getName()+"买到第" + ticketNum-- + "张票");
            }
        }
    }
}
public class Test {
    public static void main(String[] args) {
        //多个窗口抢票
        BuyTicketThread t1 = new BuyTicketThread("窗口1");
        t1.start();

        BuyTicketThread t2 = new BuyTicketThread("窗口2");
        t2.start();

        BuyTicketThread t3 = new BuyTicketThread("窗口3");
        t3.start();
    }
}

结果:

image-20210609221624087

【3】实现Runnable接口

同理,也需要实现run方法

image-20210609222007018

image-20210609222030333

例子:买车票

image-20210609223427562

image-20210609223408724

由于共享一个线程对象,TicketNum也是共享的

image-20210609223636388

【4】实现Callable接口

image-20210609223839512

image-20210609224043936

image-20210609224300116

FutureTask也实现了Runable接口

9.1.2线程的生命周期

image-20210609224634036

9.1.3线程常用方法

image-20210609224837232

(6)设置优先级setPriority

image-20210609224949364

image-20210609225125320

(7)join方法

image-20210609225508753

image-20210609225346361

运行结果:先执行主线程打印1-5,接着执行完子线程,再接着打印6-100

(8)sleep方法:人为的制造阻塞事件

image-20210609225706993

案例:

image-20210609230018945

(9)setDaemon方法:设置伴随线程

image-20210609233201508

image-20210609233050540

(10)stop:提前结束线程

image-20210609233319833

9.1.4线程安全

【1】出现问题:

(1)出现2个或者3个第10张票

image-20210609233556445

(2)出现-2, -1, 0张票

image-20210609233736891

image-20210609233800086

解决方法:加锁-》加同步-〉加同步监视器

加同步代码块:

image-20210609234113190

多个线程必须用同一把锁才能锁住

image-20210609234714283

image-20210609235016089

image-20210609235033625

image-20210609235052063

image-20210609235314728

image-20210609235411557

另一种方式:但是buyTicket()锁住的是this

image-20210609235548910

创建多个对象的时候this不是同一个,需要加上static关键字修饰,这样锁住的就是同步监视器 类.class

image-20210609235837936

image-20210609235757672

image-20210610000006194

image-20210610000035563

【5】Lock锁

Lock是一个接口,具有多个实现类,多态,扩展性好

image-20210610000239903

使用:即使有异常也能关闭锁

image-20210610000441220

image-20210610000516836

image-20210610000642571

线程同步的优缺点:

image-20210610000847861

9.1.5生产者消费者模型

image-20210610001132931

image-20210610120920582

image-20210610120944392

image-20210610121005500

image-20210610121018999

image-20210610121043712

解决方式一:

加同步代码块,synchronized

解决方式二:

加同步方法,不能直接在生产者和消费者类中加同步方法,生成的两个对象使用的是不同的锁

可以在商品类中添加同步方法

image-20210610121826220

线程通信的原理:

image-20210610122310314

image-20210610122521681

image-20210610122543005

image-20210610122645525

image-20210610122836632

注意:wait()方法和notify()方法都需要在同步方法和同步代码块中(因为在同步的基础上线程通信才是有效的)

sleep和wait的区别:sleep进入阻塞,没有释放锁。wait进入阻塞同时释放锁。

image-20210610123338744

在等待队列中可能存在多个生产者和消费者:

使用Condition中的await和signal方法

image-20210610124828006

image-20210610125544436

image-20210610125532189

生产者:

image-20210610124948024

image-20210610125104526

image-20210610125138813

消费者:

image-20210610125404060

image-20210610125455119

9.2反射

image-20210610125748488

image-20210610150141474

image-20210610145747792

9.2.1引入

美团外卖的接口:Mtwm.java

//接口定制方:美团外卖
public interface Mtwm {
    //在线支付功能
    void payOnline();
}

微信、支付宝、银行卡类:

public class Wechat implements Mtwm{
    @Override
    public void payOnline() {
        //实现微信支付的功能
        System.out.println("我点外卖使用微信支付");
    }
}

public class AliPay implements Mtwm{
    @Override
    public void payOnline() {
        //实现支付宝支付
        System.out.println("我点外卖用支付宝支付");
    }
}
public class BankCard implements Mtwm{
    @Override
    public void payOnline() {
        //银行卡支付
        System.out.println("我点外卖用银行卡支付");
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        //定义一个字符串,模拟前台的支付方式:
        String str = "支付宝";
        //String str = "微信";
        if ("微信".equals(str)) {  //避免空指针异常str有可能为空
            //微信支付
            //new Wechat().payOnline();
            pay(new Wechat());
        }
        if ("支付宝".equals(str)){
            //支付宝支付
            //new AliPay().payOnline();
            pay(new AliPay());
        }
        if ("银行卡".equals(str)){
            //银行卡支付
            pay(new BankCard());
        }
    }

    public static void pay(Wechat wc){
        wc.payOnline();
    }

    public static void pay(AliPay ap){
        ap.payOnline();
    }

    public static void pay(BankCard bc){
        bc.payOnline();
    }
}

为了提高代码的扩展性

image-20210610132255016

但是多态的扩展性还不是最好的,更好的解决方法是反射

public class Demo {
    public static void main(String[] args) throws Exception{
        //定义一个字符串,模拟前台的支付方式:
        String str = "test01.BankCard";  //实际上是微信类的全限定路径

        Class cls = Class.forName(str);
        Object o = cls.newInstance();
        Method method = cls.getMethod("payOnline");
        method.invoke(o);

    }
}

9.2.2Class类

image-20210610151507061

image-20210610151710633

image-20210610151821272

image-20210610152011991

image-20210610152052426

image-20210610152113213

image-20210610155443337

image-20210610155650187

Class c3 = Class.forName("test01.Person");

image-20210610155843191

ClassLoader loader = Test.class.getClassLoader();
Class c4 = loader.loadClass("test01.Person");

9.2.3Class类的实例的种类

image-20210610160629398

image-20210610161111620

9.2.4获取构造器和创建对象

image-20210610162135675

image-20210610162222470

指定构造器:

不填写参数,默认得到空的构造器

image-20210610162317881

image-20210610162504097

image-20210610162607005

image-20210610162640395

9.2.5获取属性

image-20210610162926699

image-20210610164849338

image-20210610164930943

image-20210610165134204

修饰符是一个具体的数字,如果需要转成字符串:

image-20210610165240642

查看属性的修饰符也可以合成一句话:

image-20210610165318158

给这个对象的score属性设置值为98

image-20210610165506479

给属性赋值,必须要有对象

9.2.6获取方法

getMethods:获取运行时的方法和所有父类的方法(被public修饰)

image-20210610165728565

image-20210610165908091

image-20210610165945149

image-20210610170101055

image-20210610170115622

image-20210610170244244

image-20210610170344096

image-20210610170429966

9.2.7获取类的接口、包、注解

image-20210610170701291

image-20210610170725058

获取包名:

image-20210610170823370

获取注解:

image-20210610170852645

9.2.8反射面试题

程序的扩展性,需要在程序运行时才确定

image-20210610171242151

原文地址:https://www.cnblogs.com/wrrr/p/14871888.html