多线程学习笔记---(基础知识)

进程与线程的简单理解

程序是指令的集合,程序跑起来就是进程。
同一个程序可以有多个进程,比如qq可以启动多个客户端程序登陆不同的账号。
进程是资源分配的最小单位。线程是cpu调度的最小单位。
进程之间不会共享资源,否则一个软件就会获取到另一个软件的密码,而线程之间可以共享内存等资源。

开启多线程的三个方式
Thread
  • 通过继承Thread类来获取多线程能力
  • 该类实现了Runnable接口,具有start方法
  • 不建议使用,存在OOP单继承的局限性
public class thread_test extends Thread{

    //使用同一个资源时还是会冲突
    //当一个线程在输出,还没来得及i--时,另一个线程执行了输出
    static int i=20;
    @Override
    public void run() {
        while (i>0){
            System.out.println(Thread.currentThread().getName()+": "+i--);
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        thread_test t1 = new thread_test();
        thread_test t2 = new thread_test();
        thread_test t3 = new thread_test();
        t1.start();
        t2.start();
        t3.start();
    }
}
Runnable
  • 实现Runnable接口
  • 需要将接口实现传递给new Thread()来获取多线程能力,用到了静态代理的方式
  • 可以建一个对象传递给多个new Thread来构建多个线程
  • 可以避免单继承局限性,推荐使用
public class Runnable_test implements Runnable{
    static int i = 20;
    @Override
    public void run() {
        while (i>0){
            System.out.println(Thread.currentThread().getName()+": "+i--);
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public static void main(String[] args) {
        Runnable_test r1 = new Runnable_test();
//        Runnable_test r2 = new Runnable_test();
//        Runnable_test r3 = new Runnable_test();
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r1);
        Thread t3 = new Thread(r1);

        t1.start();
        t2.start();
        t3.start();
    }
}
Collable
  • 可以有返回值
public class Callable_Test implements Callable<Boolean> {
    static int i = 20;
    @Override
    public Boolean call() throws Exception {
        while (i>0){
            System.out.println(Thread.currentThread().getName()+" : "+i--);
            Thread.sleep(20);
        }
        return true;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable_Test ct1 = new Callable_Test();
        Callable_Test ct2 = new Callable_Test();

        //创建线程池
        ExecutorService es = Executors.newFixedThreadPool(3);

        Future<Boolean> s1 = es.submit(ct1);
        Future<Boolean> s2 = es.submit(ct2);

        Boolean b1 = s1.get();
        Boolean b2 = s2.get();

        es.shutdown();
        
    }
}
关于Java泛型
  • 由于Collable接口使用到了泛型,我看了下面的博客文章,觉得写得比较仔细,先记录在这里,下次用到比较多的时候再深入学习。
  • https://www.cnblogs.com/jingmoxukong/p/12049160.html
  • 若使用Object作为参数类型,虽然也可以传入不同的对象,但是生成的对象相当于:Object o = new A(),只能使用object中已有的方法;但是若使用泛型,则相当于:A a = new A(),使用起来更为灵活
静态代理
  • 上面Runnable实现多线程采用了静态代理的方式,具体参考下面的笔记
  • https://www.cnblogs.com/cC-Zhou/p/9525638.html

代理类和被代理类必须实现同一个接口或者继承同一个类,重写了同一个方法
当要调用被代理类的方法时,可以通过调用代理类的同名方法实现
通过代理类来调用被代理类的方法,通常会在调用方法的前后进行一个功能的附加和增强

lambda表达式
  • 只有一个抽象方法的接口为函数式接口,这种接口的实现类可以用lambda表达式表示
public class InnerClassTest {
    public static void main(String[] args) {
        saticInner saticInner = new saticInner();
        saticInner.run();

        //3.局部内部类,定义在方法内部的类,其对象创建要在类定义的后面
        class partInner implements innerRun{
            @Override
            public void run() {
                System.out.println("part inner class test");
            }
        }

        partInner partInner = new partInner();
        partInner.run();

        //4.匿名内部类,在创建对象的同时重写方法,没有名字
        innerRun r = new innerRun() {
            @Override
            public void run() {
                System.out.println("anonymous class");
            }
        };
        r.run();

        //5.lambda表达式。
        //因为只有一个方法,直接在花括号内写重写方法的表达式即可
        //innerRun lanbdaTest = () -> {System.out.println("lambda 1");};
        //只有一个表达式的情况下可以去掉花括号
        //innerRun lanbdaTest = () -> System.out.println("lambda 1");

        //使用参数的情况下
        //lambadTest lanbdaTest = (int a) -> {System.out.println(a);};

        //一个参数的情况下可以去掉括号,多个参数的情况下不行
        //可以同时去掉所有参数的类型
        lambadTest lanbdaTest =  a -> {System.out.println("lambda 1");};
    }

    //2.静态内部类,定义在类内部的静态类
    static class  saticInner implements innerRun{
        @Override
        public void run() {
            System.out.println("static inner class test");
        }
    }
    

}

//1.普通实现类
class normalClass implements innerRun{
    @Override
    public void run() {
        System.out.println("normal class test");
    }
}


interface innerRun{
    void run();
}

interface lambadTest{
    void run0(int a);
}
停止线程的方式
  • 一般不推荐通过thread自带的stop,destory等方法来停止线程,已废弃。
  • 推荐通过设置标志位停止
public class stopThread implements Runnable{

    //结束标志
    boolean flag=true;
    int i = 0;

    @Override
    public void run() {
        //设置一个开始条件
        while (flag){
            System.out.println(i++);
        }
    }
    public void stop(){
        flag=false;
    }

    public static void main(String[] args) {
        stopThread st = new stopThread();
        Thread thread = new Thread(st);
        thread.start();
        for (int j =0 ;j<1000;j++){
            System.out.println("main"+j);
        }

        //通过这个方法使得当前对象的flag为false,从而停止线程运行
       st.stop();
    }
}
sleep–线程休眠
  • 通过thread.sleep()方法可以模拟网络延迟
  • 还可以进行倒计时
public class sleepTestr {
    public static void main(String[] args) {
        countDown();
    }

    public static void countDown(){
        for (int i = 10; i > 0; i--) {
            Date date = new Date(System.currentTimeMillis());
            System.out.println(new SimpleDateFormat("HH:mm:ss").format(date));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
yield–线程礼让
  • 礼让是让线程从运行到就绪,让CPU重新分配,但不一定成功,因为还是要看cpu的分配
public class yieldTest implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+" start");
        //Thread.yield();
        System.out.println(Thread.currentThread().getName()+" stop");
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new yieldTest());
        Thread t2 = new Thread(new yieldTest());
        t1.start();
        t2.start();

    }
}
join–线程强行执行
  • 让join的线程先执行
public class joinTest implements Runnable{
    @Override
    public void run() {
        for (int i = 100; i > 0; i--) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new joinTest());
        t1.start();
        for (int i = 200; i > 0; i--) {
            if (i==100){
                t1.join();
            }
            System.out.println("main"+i);
        }
    }
}
线程状态
  • thread.getState:获取线程的状态
线程优先级
  • 主线程的优先级是默认的
  • 必须先设置优先级,再启动线程
  • 线程优先级最大是10,最小是1,超过范围会报错
  • 默认值都是5,意味着获取调度的概率都相同
  • 优先级高不一定会优先执行,只能说优先的概率比较高
public class priorityTest implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+": "+Thread.currentThread().getPriority());
    }

    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getPriority());

        Thread t1 = new Thread(new priorityTest(), "t1");
        t1.setPriority(1);
        //设为守护线程
        t1.setDaemon(true);
        t1.start();

        Thread t2 = new Thread(new priorityTest(), "t2");
        t2.setPriority(7);
        t2.start();

        Thread t3 = new Thread(new priorityTest(), "t3");
        t3.setPriority(Thread.MAX_PRIORITY);
        t3.start();
    }
}
守护线程
  • JVM虚拟机必须保证用户线程执行完毕才会退出运行,但是不必等待守护线程执行完毕
  • 后台记录操作日志,监控内存,垃圾回收等都是守护线程
  • thread.seydaemon(true)表示设为守护线程,默认值为false,意味着即使该线程没有运行完也JVM也可以退出
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java是一种广泛使用的编程语言,有简单、面向对象、跨平台等特点。下面是Java学习的一些重要知识点和学习笔记: 1. Java基础: - 数据类型:Java提供了多种数据类型,包括基本数据类型和引用数据类型。 - 控制流程:学习如何使用条件语句(if-else、switch)、循环语句(for、while)等控制程序的流程。 - 数组:了解如何声明、初始化和操作数组。 - 方法:学习如何定义和调用方法,以及方法的参数和返回值。 - 类和对象:理解类和对象的概念,学习如何定义类、创建对象和使用类的成员变量和方法。 - 继承和多态:掌握继承和多态的概念,了解如何使用继承创建子类,并实现方法的重写和多态的应用。 2. 面向对象编程: - 封装:学习如何使用访问修饰符(public、private、protected)来控制类的成员的访问权限。 - 继承:了解继承的概念和作用,学习如何使用extends关键字创建子类。 - 多态:理解多态的概念和实现方式,学习如何使用父类引用指向子类对象,实现方法的动态绑定。 3. 异常处理: - 异常的分类:了解异常的分类(Checked Exception和Unchecked Exception)和常见的异常类型。 - 异常处理机制:学习如何使用try-catch语句捕获和处理异常,以及使用throws关键字声明方法可能抛出的异常。 4. 输入输出: - 文件操作:学习如何读写文件,包括使用File类、字节流和字符流等。 - 序列化:了解对象的序列化和反序列化,学习如何将对象保存到文件或网络中。 5. 集合框架: - 学习Java提供的集合框架,包括List、Set、Map等常用的集合类,以及它们的特点和用法。 6. 多线程编程: - 学习如何创建和管理线程,了解线程同步和线程间通信的方法。 7. 数据库连接: - 学习如何使用Java连接数据库,执行SQL语句,进行数据的增删改查操作。 以上是Java学习的一些重要知识点和学习笔记,希望对你有帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值