Java基础(三)- 多线程、网络通信、单元测试、反射、注解、动态代理

多线程基础

线程:一个程序内部的一条执行流程,只有一条执行流程就是单线程

java.lang.Thread代表线程

主线程退出,子线程存在,进程不会退出

可以使用jconsole查看

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

创建线程

有多个方法可以创建线程

  • 继承Thread类

    • 优点:编码简单
    • 缺点:无法继承其他类,不利于功能的扩展
  • 实现Runnable接口

    • 优点:任务类只是实现了接口,可以继续继承其他类、实现其他接口,扩展性强
    • 缺点:需要多创建一个Runnable对象
  • 实现Callable接口和FutureTask类

    • 优点:可以返回线程执行结束之后的结果
    • 缺点:编码复杂

    执行为什么是start()?

    使用run不是多线程, 相当于直接调用方法 还是单线程

    start->start0(本地方法 JVM调用 C/C++实现的)
    

方法一

public class Demo1 {
   
    public static void main(String[] args) throws Exception {
   
        //main是主线程执行的

        //新建了一个t线程
        Thread t = new primeThread();
        //启动线程 start自动调用run方法 必须要调用start方法
        //如果是t.run() 相当于直接调用方法 还是单线程
        t.start();

        for (int i = 0; i < 5; i++) {
   
            System.out.println("主线程");
            Thread.sleep(500);
        }
    }
}

class primeThread extends Thread{
   
    public primeThread(){
   

    }

    @Override
    public void run() {
   
        //描述线程的执行的任务
        for (int i = 0; i < 5; i++) {
   
            System.out.println("子线程");
            try {
   
                Thread.sleep(500);
            } catch (Exception e) {
   
                e.printStackTrace();
            }
        }
    }
}

方法二

public class Demo2 {
   
    public static void main(String[] args) throws Exception {
   
        //runnable只是一个任务对象
        Runnable target = new prime1Thread();
        //需要线程对象接受任务对象 开辟新的线程
        new Thread(target).start();
        for (int i = 0; i < 5; i++) {
   
            System.out.println("主线程");
            Thread.sleep(500);
        }
    }
}

class prime1Thread implements Runnable{
   
    @Override
    public void run() {
   
        for (int i = 0; i < 5; i++) {
   
            System.out.println("子线程");
            try {
   
                Thread.sleep(500);
            } catch (Exception e) {
   
                e.printStackTrace();
            }
        }
    }
}


//可以使用匿名内部类
public class Demo2 {
   
    public static void main(String[] args) throws Exception {
   
        //需要线程对象进行调用任务对象开辟新的线程
        new Thread(()-> {
   
                for (int i = 0; i < 5; i++) {
   
                    System.out.println("子线程");
                    try {
   
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
   
                        throw new RuntimeException(e);
                    }	
                }
        }).start();
        for (int i = 0; i < 5; i++) {
   
            System.out.println("主线程");
            Thread.sleep(500);
        }
    }
}

方法三

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Demo3 {
   
    public static void main(String[] args) throws ExecutionException, InterruptedException {
   
        //创建一个Callable对象
        Callable<String> myCallable = new MyCallable(100);

        // 把Callable的对象封装成一个FutureTask对象(任务对象)
        // 未来任务对象的作用?
        // 1、是一个任务对象,实现下Runnable对象
        // 2、可以在线程执行完毕之后,用未来任务对象调用get方法获取线程执行完毕的结果
        //也可以使用匿名内部类
        FutureTask<String> stringFutureTask = new FutureTask<>(myCallable);

        new Thread(stringFutureTask).start();

        //获取结果会阻塞线程
        System.out.println(stringFutureTask.get());

    }
}


//泛型
class MyCallable implements Callable<String>{
   
    private  int n;

    public MyCallable(int n) {
   
        this.n = n;
    }

    @Override
    public String call() throws Exception {
   
        int sum = 0;
        for (int i = 1; i <= n; i++) {
   
            sum+=i;
        }
        return sum+"";
    }
}

线程方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • setPriority()更改线程的优先级
  • getPriority()获取线程的优先级
  • interrupt中断线程,并不是真正的结束线程 所以一般用于中断正在休眠的线程
  • yield线程的礼让,不一定礼让成功(和join相反,线程的插队)
public class Demo4 {
   
    public static void main(String[] args) throws InterruptedException {
   
        Thread t1 = new Thread1("1号线程");
//        t1.setName("1号线程");//启动之前取名字
        t1.start();
        t1.join();
//        System.out.println(t1.getName());

        Thread t2 = new Thread1("2号线程");
//        t2.setName("2号线程");//启动之前取名字
        t2.start();
        t2.join();//t2线程执行完成之后才能继续往下执行
//        System.out.println(t2.getName());

        Thread t3 = new Thread1("3号线程");
        t3.start();
        t3.join();

        Thread m = Thread.currentThread();
        m.setName("最牛逼的名字");
//        System.out.println(m.getName());
        for (int i = 0; i < 5; i++) {
   
            System.out.println(m.getName()+"输出"+(i+1));
        }
    }
}

class Thread1 extends Thread{
   
    public Thread1(String name) {
   
        super(name);
    }

    @Override
    public void run() {
   
        Thread t= Thread.currentThread();
        for (int i = 0; i < 3; i++) {
   
            System.out.println("子线程"+t.getName()+"输出:"+(i+1));
        }
    }
}

线程终止

  • 当线程执行完成时,自动退出
  • 使用变量来控制run方法退出的方式停止线程

守护线程

当所有的用户线程都退出时,守护线程自动退出

垃圾回收机制

public class Test {
   
    public static void main(String[] args) {
   
        //子线程设置为守护线程
        myDaemonThread myDaemonThread = new myDaemonThread();
        myDaemonThread.setDaemon(true);
        myDaemonThread.start();
        for (int i = 0; i < 10; i++) {
   
            System.out.println(Thread.currentThread().getName() + " 执行");
            try {
   
                Thread.sleep(1000);
            } catch (InterruptedException e) {
   
                throw new RuntimeException(e);
            }
        }

    }
}

/*
守护线程:
当用户线程退出后 子线程也自动退出
 */
class myDaemonThread extends Thread {
   
    @Override
    public void run() {
   
        while (true) {
   
            System.out.println(Thread.currentThread().getName() + " 正在执行");
            try {
   
                Thread.sleep(500);
            } catch (InterruptedException e) {
   
                throw new RuntimeException(e);
            }
        }
    }
}

线程安全

概念

多个线程同时操作同一个共享资源的时候可能出现业务安全问题

模拟线程安全问题

package Thread_;

public class Demo5 {
   

    public static void main(String[] args) {
   
        Thread xiaoHong = new DrawThread("小红");
        Thread xiaoMing = new DrawThread("小明");
        xiaoMing.start();
        xiaoHong.start();

    }
}
class Account{
   
    private static double moneys = 100000;
    private Account(){
   }

    public static double getMoneys() {
   
        return moneys;
    }

    public static void setMoneys(double moneys) {
   
        Account.moneys = moneys;
    }

    public static boolean drawMoneys(double moneys){
   
        String name = Thread.currentThread().getName();
        if (moneys>Account.getMoneys()){
   
            System.out.println(name+"来取钱,钱不够");
            return false;
        }

        Account.moneys-=moneys;
        System.out.println(name+"来取钱,取钱成功,剩余"+Account.moneys);
        return true;
    }
}

class DrawThread extends Thread{
   
    public DrawThread(String name) {
   
        super(name);
    }

    @Override
    public void run() {
   
        Account.drawMoneys(100000.0);
    }
}

线程同步

认识线程同步

多个线程实现先后依次访问共享资源

**加锁:**每次只允许一个线程加锁,加锁之后才能访问,访问完毕之后自动解锁,然后其他线程才能再加锁继续

方法一:同步代码块

把访问共享资源的核心代码给上锁,保证线程安全

synchronized(同步锁){
   
    访问共享资源的核心代码
}

对于当前同时执行的线程来说,同步锁必须是同一把(同一对象

锁对象的选择:

  • 实例对象:使用this
  • 静态对象:使用类型.class
public class Demo5 {
   

    public static void main(String[] args) throws InterruptedException {
   
        Account acc1 = new Account(100000);
        Thread xiaoHong = new DrawThread("小红",acc1);
        Thread xiaoMing = new DrawThread("小明",acc1);
        xiaoMing.start();
        xiaoHong.start();

        Account acc2 = new Account(100000);
        Thread daGang = new DrawThread("大纲",acc2);
        Thread daLi = new DrawThread("大力",acc2);
        daGang.start();
        daLi.start();
    }
}

class Account {
   
    private double moneys;

    public Account() {
   
    }

    public Account(double moneys) {
   
        this.moneys = moneys;
    }

    public double getMoneys() {
   
        return moneys;
    }

    public void setMoneys(double moneys) {
   
        this.moneys = moneys;
    }

    public void drawMoneys(double moneys) throws InterruptedException {
   
        String name = Thread.currentThread().getName();
        /*
         * 两个人同时竞争lock这个对象(这把锁),只有一个人能够得到
         * 上锁之后另外一个人要等待开锁
         *
         * 但是这个lock对于所有的对象是一个锁
         * 一个对象上锁的时候 和该对象无关的对象也无法进入核心代码
         * 非static建议使用 this
         * static建议使用 ClassName.class
         * */
        synchronized (this) {
   
//            Thread.sleep(5000); 测试
            if (moneys > this.getMoneys()) {
   
                System.out.println(name + "来取钱,钱不够");
            } else {
   
                this.moneys -= moneys;
                System.out.println(name + "来取钱,取钱" + moneys + "成功,剩余" + this.moneys);
            }
        }
    }
}

class DrawThread extends Thread {
   
    private Account acc;
    public DrawThread(String name,Account acc) {
   
        super(name);
        this.acc = acc;
    }

    @Override
    public void run() {
   
        try {
   
            acc.drawMoneys(100000);
        } catch (InterruptedException e) {
   
            throw new RuntimeException(e);
        }
    }
}

方法二:同步方法

访问共享资源的核心方法给上锁

修饰符 synchronized 返回值类型 方法名称(形参列表){
   
    操作共享资源的代码
}
public class Demo5 {
   

    public static void main(String[] args) throws InterruptedException {
   
        Account acc1 = new Account(100000);
        Thread xiaoHong = new DrawThread("小红", acc1);
        Thread xiaoMing = new DrawThread("小明", acc1);
        xiaoMing.start();
        xiaoHong.start();

        Account acc2 = new Account(100000);
        Thread daGang = new DrawThread("大纲", acc2);
        Thread daLi = new DrawThread("大力", acc2);
        daGang.start();
        daLi.start();
    }
}

class Account {
   
    private double moneys;

    public Account() {
   
    }

    public Account(double moneys) {
   
        this.moneys = moneys;
    }

    public double getMoneys() {
   
        return moneys;
    }

    public void setMoneys(double moneys) {
   
        this.moneys = moneys;
    }

    /*
    有一个隐含的锁 实例方法是 this  静态方法是 类型.class
     */
    public synchronized void drawMoneys(double moneys) throws InterruptedException {
   
        String name = Thread.currentThread().getName();
        if (moneys > this.getMoneys()) {
   
            System.out.println(name + "来取钱,钱不够");
        } else {
   
            this.moneys -= moneys;
            System.out.println(name + "来取钱,取钱" + moneys + "成功,剩余" + this.moneys);
        }
    }
}

class DrawThread extends Thread {
   
    private Account acc;

    public DrawThread(String name, Account acc) {
   
        super(name);
        this.acc = acc;
    }

    @Override
    public void run() {
   
        try {
   
            acc.drawMoneys(100000);
        } catch (InterruptedException e) {
   
            throw new RuntimeException(e);
        }
    }
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

方法三:Lock锁

Lock锁是IDK5开始提供的一个新的锁定操作,通过它可以创建出锁对象进行加锁和解锁,更灵活、更方便、更强大

Lock是接口,不能直接实例化,可以采用它的实现类**ReentrantLock**来构建Lock锁对象。

package Thread_;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Demo5 {
   

    public static void main(String[] args) throws InterruptedException {
   
        Account acc1 = new Account(100000);
        Thread xiaoHong = new DrawThread("小红", acc1);
        Thread xiaoMing = new DrawThread("小明", acc1);
        xiaoMing.start();
        xiaoHong.start();

        Account acc2 = new Account(100000);
        Thread daGang = 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值