学习笔记 2021.10.27

2021.10.27

多线程

简介

image-20211027203932238

  • 注意进程是系统资源分配的这么一个概念。
  • 真正执行的是线程。

基本的一些操作系统层面的知识,有助于对计算机基本的理解:

image-20211027204139297

线程的创建

基本的三种创建方法

image-20211027204250479

首先了解继承了线程类的两种方法的调用:

image-20211027204947491

  • 即run方法是完全的单路的按顺序执行各种线程和主线程
  • 而start方法则是对各个线程并发的进行执行。此时注意具体的线程执行是由CPU去调度安排,不一定立即执行的。

创建方法一

public class testthread extends Thread{
    public void run()
    {
        for (int i = 0; i < 20; i++) {
            System.out.println("我在在自定义线程"+i);
        }
    }

}
package Thread;
//创建线程的方式1 继承thread类
public class Demo01 {
    public static void main(String[] args) {
        testthread tt = new testthread();
        tt.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("我在在主线程"+i);
        }
    }

这种方法主要的就是记住继承类和对run方法的重写。

对前面所说的并发的概念的解释:

image-20211027205419012

即宏观上可以看到是同时执行的,即并发的概念。

创建方法2

package Thread;//实现runnable接口

public class Runabletest implements Runnable{
    public void run()
    {
        for (int i = 0; i < 20; i++) {
            System.out.println("我在在自定义线程"+i);
        }
    }

}
package Thread;//创建方式二,通过runnable接口实现

public class Demo02 {

    public static void main(String[] args) {
        Runnable rr =new Runabletest();
        Thread tt =new Thread(rr);
        tt.start();

        for (int i = 0; i < 20; i++) {
            System.out.println("我在在主线程"+i);
        }
    }
}

image-20211027210202598

其实因为thread本身这个类也是继承了这个接口的,具体区别就只有位于哪一层重写方法的区别。

两种方法的比较

image-20211027210339186

因此经常选用第二个创建方法的好处即在于方便调用。

下面即是一个对于通过接口创建线程的一个简单的小例子来理解这么创建的意义:

image-20211027211351072

具体代码实现:

package Thread;//龟兔赛跑模拟

public class Demo03 implements Runnable{
    private String winner;

    public void run()
    {

        for (int i = 0; i <=100 ; i++) {
            if(Thread.currentThread().getName().equals("兔子") && i%10 == 0)
            {
                try {
                    Thread.sleep(2);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            boolean flag = gameover(i);
            if (flag)
            {
                break;
            }
            System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
        }
    }

    public  boolean gameover(int step)
    {
        if(winner!=null)
            return true;
        {
            if (step == 100)
            {
                winner = Thread.currentThread().getName();
                System.out.println(winner+"赢了");
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        Demo03 rr =new Demo03();

        new Thread(rr,"兔子").start();
        new Thread(rr,"乌龟").start();

    }
}

上面的例子主要就是体现

  1. 在run方法中进行的操作都是实时运行中需要判断或者变化的操作,自然也就包括了使线程停止,比如说break的使用。
  2. 通过main方法里的调用可以看出通过接口来创建线程的话,可以在线程内去实现更多的逻辑,使得线程对象有着更多的适用性。

创建方法3(了解)

image-20211027212811171

这里就不自己去写了,就稍微知道有这个东西就可以了。

image-20211027213005185

最多就是执行服务这个类,后面也会涉及。但对于这种创建方法相关的也就是具体的一些线性过程的区别,有个概念就可以了。

静态代理

用一个实际类似的例子来类比静态代理的模式。

image-20211027214019085

具体代码相关:

package Thread.Demo04;

public class App {
    public static void main(String[] args) {
        You yy =new You();
        marrycom mm = new marrycom(yy);
        mm.marry();
    }

}

interface Marry
{
    void marry();
}

class You implements Marry
{
    public void marry()
    {
        System.out.println("结婚了");
    }
}

class marrycom implements Marry
{
    private Marry tt;

    public marrycom(Marry tt) {
        this.tt = tt;
    }

    @Override
    public void marry() {
        before();
        this.tt.marry();
        after();
    }

    private void before()
    {
        System.out.println("结婚前");
    }

    private void after()
    {
        System.out.println("结婚后");
    }
}

image-20211027214647000

具体的总结:

  1. 真实对象和代理对象都要实现同一个接口。
  2. 代理对象要代理真实的角色。

好处:

  1. 代理对象可以做很多真实对象不做的事情。
  2. 真实对象专注于做自己的事情。

一些自己的理解:

  • 代理对象和真实对象是通过接口联系起来的,区别即在于真实对象只需要在接口中完成自己必须完成的事情,但是代理对象可以在接口中实现更多的功能,进行更多的处理。
  • 类比于通过创建方法2创建线程并且执行的过程,可以发现thread就可以看作是一个静态代理,重写runnable接口的对象即是真实对象。即thread不仅可以实现run这么一个过程,还可以对run的其他相关的多进行一些操作。而此时重写runnable接口的真实对象就专注于写好run过程中的逻辑即是了。
posted @ 2021-10-27 21:57  damndamit  阅读(54)  评论(0)    收藏  举报