《JAVA300集》多线程_基础-day20

目录

多线程

静态代理设计模式

Lambda表达式简化线程

线程状态

终止线程的典型方式

暂停线程执行

线程的联合

线程的常用方法

线程的优先级

守护线程


多线程

静态代理设计模式

之前讲通过Runnable接口启动多线程的操作,需要借助thread类的对象,这个thread类可以成为静态代理。

静态代理:这个类是提前写好的,可以直接拿来用。

动态代理: 这个类是在运行过程中,动态构建出来的,可以理解为临时构建出来的。

/*
* 静态代理
* 公共接口:
* 1、真实角色
* 2、代理角色
* */
public class StaticProxy {
    public static void main(String[] args) {
        new WeddingCompany(new You()).happyMarry();
    }
}

interface Marry{
    void happyMarry();
}
class You implements Marry{
    @Override
    public void happyMarry() {
        System.out.println("我和小机智奔月啦~");
    }
}
//代理角色
class WeddingCompany implements Marry{
    //真实角色
    private Marry target;
    public WeddingCompany(Marry target){
        this.target = target;
    }
    @Override
    public void happyMarry() {
        ready();
        this.target.happyMarry();
        after();
    }
    private void ready(){
        System.out.println("准备好火箭");
    }
    private void after(){
        System.out.println("运送物质去月球");
    }
}

Lambda表达式简化线程

/*
* Lambda表达式简化只使用一次的线程使用
* */

//好处,LambdaThread使用的时候才会编译
public class LambdaThread{
    //静态内部类
    static class Test implements  Runnable{
        @Override
        public void run() {
            for (int i = 0; i < 3; i++) {
                System.out.println("一边听歌1");
            }
        }
    }

    public static void main(String[] args) {
        //局部内部类
        class Test2 implements  Runnable{
            @Override
            public void run() {
                for (int i = 0; i < 3; i++) {
                    System.out.println("一边听歌2");
                }
            }
        }

        new Thread(new Test()).start();
        new Thread(new Test2()).start();

        //匿名内部类,必须借助接口或者父类
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 3; i++) {
                    System.out.println("一边听歌3");
                }
            }
        }).start();

        //匿名内部类简化 lambda (只能是一个方法)
        new Thread(()-> {
                for (int i = 0; i < 3; i++) {
                    System.out.println("一边听歌4");
            }
        }).start();

        for(int i=0;i<3;i++){
            System.out.println("一边coding");
        }
    }
}

 new Thread(()-> {System.out.println("一边听歌4"); }).start();

线程状态

一个线程对象在整个生命周期内,需要经历5个状态。

新生状态(new):用new关键字建立一个线程对象后,该线程对象就处于新生状态。处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态。

就绪状态(Runnable):处于就绪状态的线程已经具备了运行条件,、处于“线程就绪队列”,等待系统为其分配CPU。当系统选定一个等待执行的Thread对象后,就绪状态就会进入执行状态。一旦获得CPU,线程就进入运行状态并自动调用自己的run方法。

线程进入就绪状态的四种原因:

1. 新建线程:调用start()方法,进入就绪状态;

2. 阻塞线程:阻塞解除,进入就绪状态;

3. 运行线程:调用yield()方法,直接进入就绪状态;

4. 运行线程:JVM将CPU资源从本线程切换到其他线程。

运行状态(Running): 在运行状态的线程执行自己run方法中的代码,直到调用其他方法而终止或等待某资源而阻塞或完成任务而死亡。如果在给定的时间片内没有执行结束,就会被系统给换下来回到就绪状态。也可能由于某些“导致阻塞的事件”而进入阻塞状态。

阻塞状态(Blocked):阻塞指的是暂停一个线程的执行以等待某个条件发生(如某资源就绪)。有4种原因会导致阻塞:

 1. 执行sleep()方法,使当前线程休眠,进入阻塞状态。当指定的时间到了后,线程进入就绪状态。

 2. 执行wait()方法,使当前线程进入阻塞状态。当使用nofity()方法唤醒这个线程后,它进入就绪状态。

 3. 线程运行时,某个操作进入阻塞状态,比如执行IO流操作(read()/write()方法本身就是阻塞的方法)。只有当引起该操作阻塞的原因消失后,线程进入就绪状态。

 4. join()线程联合: 当某个线程等待另一个线程执行结束后,才能继续执行时,使用join()方法。

死亡状态(Terminated):

死亡状态是线程生命周期中的最后一个阶段。线程死亡的原因有两个。一个是正常运行的线程完成了它run()方法内的全部工作; 另一个是线程被强制终止。

注意:

(1)运行状态被暂停后,再开启是要先进入就绪状态。

(2)当一个线程进入死亡状态以后,就不能再回到其它状态了。

终止线程的典型方式

通常的做法是提供一个boolean型的终止变量,当这个变量置为false,则终止线程的运行。

/*
* 终止线程
* 1、线程正常执行完毕-次数
* 2、外部干涉-加入标识
* */
public class TerminateThread implements Runnable{
    //加入标识,标记线程体是否可以运行
    private boolean flag = true;
    private String name;

    public TerminateThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        int i=0;
        //关联标识,ture运行,false停止
        while(flag){
            System.out.println(name+"--"+i++);
        }
    }

    public void treminate(){
        this.flag = false;
    }
    public static void main(String[] args) throws InterruptedException {
        TerminateThread tt = new TerminateThread("gaosan");
        new Thread(tt).start();
        for(int i=0;i<=10;i++){
            sleep(1);
            if(i==8){
                tt.treminate(); //外部控制线程中止
                System.out.println("线程中止");
            }
            System.out.println(i);
        }

    }
}

暂停线程执行

常用的方法有sleep()和yield()方法,这两个方法的区别是:

1. sleep()方法:可以让正在运行的线程进入阻塞状态,直到休眠时间满了,进入就绪状态。

2. yield()方法:可以让正在运行的线程直接进入就绪状态,让出CPU的使用权。

/*
* yield 让出CPU的调度
* */
public class YieldDemo01 {
    public static void main(String[] args) {
        Myyield my = new Myyield();
        new Thread(my,"a").start();
        new Thread(my,"b").start();
    }
}

class Myyield implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"--start");
        Thread.yield(); //礼让
        System.out.println(Thread.currentThread().getName()+"--end");
    }
}

线程的联合

 线程A在运行期间,可以调用线程B的join()方法,让线程B和线程A联合。这样,线程A就必须等待线程B执行完毕后,才能继续执行

所以线程的联合可以理解为插队线程。

public class BlockedJoin {
    public static void main(String[] args) {
        System.out.println("父亲和儿子买烟的故事");
        Thread father = new Thread(new Father());
        father.start();
    }
}

class Father extends Thread{
    @Override
    public void run() {
        System.out.println("父亲想抽烟,但是没有烟了");
        System.out.println("让儿子去买软中华");
        Thread t = new Thread(new Son());
        t.start();
        try{
            t.join();
            System.out.println("父亲开始抽烟");
        }catch (InterruptedException e){
            e.printStackTrace();
            System.out.println("儿子没有回来");
        }
    }
}

class Son extends Thread{
    @Override
    public void run() {
        System.out.println("接过父亲的钱出去了");
        System.out.println("买烟的路上时间");
        for(int i=1;i<10;i++){
            System.out.println(i+"秒过去了");
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        System.out.println("儿子手拿一包烟回来了");
    }
}

运行结果: 

t.join();

线程的常用方法

public class InfoTest {
    public static void main(String[] args) throws InterruptedException {
        System.out.println(Thread.currentThread().isAlive());

        //设置名称:真实角色+代理角色
        MyInfo info = new MyInfo("gaosan");
        Thread t = new Thread(info);
        t.setName("高三");
        t.start();
        t.sleep(100);
        System.out.println(t.isAlive());
    }
}
class MyInfo implements Runnable{
    private  String name;
    public MyInfo(String name) {
        this.name = name;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"----"+name);
    }
}

线程的优先级

  1. 处于就绪状态的线程,会进入“就绪队列”等待JVM来挑选。

  2. 线程的优先级用数字表示,范围从1到10,一个线程的缺省优先级是5。

  3. 使用下列方法获得或设置线程对象的优先级。

 int getPriority();

 void setPriority(int newPriority);

  注意:优先级低只是意味着获得调度的概率低。并不是绝对先调用优先级高的线程后调用优先级低的线程。

public class TestThread {
    public static void main(String[] args) {
        Thread t1 = new Thread(new MyThread(), "t1");
        Thread t2 = new Thread(new MyThread(), "t2");
        t1.setPriority(1);
        t2.setPriority(10);
        t1.start();
        t2.start();
    }
}

守护线程

线程分为用户线程和守护线程。守护线程是为用户线程服务的,当用户线程执行完成后,无论守护线程有没有执行完,JVM都会关闭。默认线程都是用户线程。

/*
* 守护线程
* */
public class DaemonTest {
    public static void main(String[] args) {
        God god = new God();
        People you = new People();
        Thread t = new Thread(god);
        t.setDaemon(true); //将用户线程改为守护线程
        t.start();
        new Thread(you).start();
    }
}

class People extends Thread{
    @Override
    public void run() {
        for(int i=0;i<=10;i++){
            System.out.println("happy");
        }
    }
}
class God extends Thread{
    @Override
    public void run() {
        while(true){
            System.out.println("God bless you");
        }
    }
}
t.setDaemon(true); //将用户线程改为守护线程

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值