zoukankan      html  css  js  c++  java
  • Java学习笔记44(多线程一:Thread类)

    多线程的概念:略

    多线程的目的:提高效率

    主线程:

    package demo;
    //主线程
    public class Demo {
        public static void main(String[] args) {
            function();
            System.out.println(1);
        }
        
        public static void function(){
            for (int i = 0; i < 10000; i++) {
                System.out.println(i);
            }
        }
    }

    这段简单的代码,我们发现:

    必须要先执行方法输出完10000次的数字后才可以打印第二行的数字1

    那么有没有方法,可以做到在执行方法的同时执行第二行的输出?

    Thread类

    创建新线程的两种方法:

    第一种:

    package demo;
    
    public class SubThread extends Thread {
        //重写run方法
        public void run(){
            for(int i = 0 ; i< 50 ; i++){
                System.out.println(i+"run");
            }
        }
    }
    package demo;
    
    public class ThreadDemo {
        public static void main(String[] args) {
            SubThread st1 = new SubThread();
            st1.start();
            for (int i = 0; i < 50; i++) {
                System.out.println(i+"main");
            }
        }
    }

    这里输出时候,发现打印的run和main随机出现,交错出现,而不像以前那样按顺序打印

    原因:创建了新的线程,两条线程由cpu选择执行,我们无法控制

    start方法开启新的线程,继承了Thread类因为只有继承了它才可以操作线程

    重写run方法因为,Thread类本身没有写入有意义的run方法,相当于一个模板,供开发者使用

    线程名:

    每个线程都有自己的名字,主线程名:main,其他新建线程默认名:Thread-n

    获取、修改线程名:

    package demo1;
    
    public class NameThread extends Thread {
        public void run(){
            System.out.println(super.getName());
            //输出:默认是Thread-0,如果修改了,就是hello
        }
    }
    package demo1;
    
    public class ThreadDemo {
        public static void main(String[] args) {
            NameThread nt1 = new NameThread();
            nt1.setName("hello");
            //修改线程名为hello,主线程不能改名
            nt1.start();
            
            Thread t = Thread.currentThread();
            System.out.println(t.getName());
            //输出:main
        }
    }

    Thread类的一个实用方法:

    package demo1;
    
    public class ThreadDemo {
        public static void main(String[] args) throws InterruptedException {
            for (int i = 0; i < 10; i++) {
                Thread.sleep(1000);
                System.out.println(i);
            }
            //每次打印都会等待一秒,参数是毫秒值
        }
    }

    第二种创建线程方法:

    package demo1;
    
    public class SubRunnable implements Runnable {
        public void run() {
            for (int i = 0; i < 50; i++) {
                System.out.println(i + "run");
            }
        }
    }
    package demo1;
    
    public class ThreadDemo {
        public static void main(String[] args) {
            SubRunnable sr1 = new SubRunnable();
            Thread t1 = new Thread(sr1);
            t1.start();
            for (int i = 0; i < 50; i++) {
                System.out.println(i + "main");
            }
        }
    }

    这种方式好处:

    1.接口可以多实现,避免了单继承的局限性

    2.线程和方法分离,更符合面向对象的特点

    3.资源实现共享

    这两种方式可以实用匿名内部类实现:

    package demo1;
    
    public class ThreadDemo {
        public static void main(String[] args) {
            // 继承方式
            new Thread() {
                public void run() {
                    System.out.println("1");
                }
            }.start();
    
            // 实现接口方式
            new Thread(new Runnable() {
                public void run() {
                    System.out.println(2);
                }
            }).start();
    
        }
    }

    线程的状态:

    1.新建状态:new Thread()创建线程对象

    2.运行状态:使用了start()方法进入运行状态

    3.退出状态:run方法结束,或者调用了stop方法(已过时,不建议实用)

    4.阻塞状态:有时候使用了start方法,但不一定立即运行,或者运行之后CPU由于一些原因不再分配,由运行状态转到阻塞状态

    5.休眠状态:前边提到的sleep方法就是这种状态,也有可能转到阻塞状态或者运行状态

    6.等待状态:wait方法,无限等待,notify方法可以唤醒线程,可能转到运行或阻塞状态

    注意:受阻塞是等待CPU的资源,休眠等待是放弃CPU的执行

    线程池的概念:

     一个容器,存入多个线程,需要时候,拿出执行,

    运行结束后线程再回到容器中,这种方式可以提高效率

    实现线程池:

    package demo1;
    
    public class ThreadPoolRunnable implements Runnable {
        public void run(){
            System.out.println(Thread.currentThread().getName()+"线程提交任务");
            //输出: pool-1-thread-1线程提交任务
            //        pool-1-thread-2线程提交任务
        }
    package demo1;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class ThreadPoolDemo {
        public static void main(String[] args) {
            //调用工厂类的方法创建线程池
            ExecutorService es1 = Executors.newFixedThreadPool(2);
            es1.submit(new ThreadPoolRunnable());
            es1.submit(new ThreadPoolRunnable());
            //运行后不会停
            
            es1.shutdown();//销毁线程池,不常用
        }
    }

    实现线程的Callable接口方式:

    它弥补了Runnable方式的缺陷:无法抛出异常,并且有返回值

    使用方法和Runnable方式基本一致:

    示例:

    package demo1;
    
    import java.util.concurrent.Callable;
    
    public class ThreadPoolCallable implements Callable<String>{
        public String call(){
            return "a";
        }
    }
    package demo1;
    
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class ThreadPoolDemo {
        public static void main(String[] args) throws InterruptedException, ExecutionException {
            ExecutorService es1 = Executors.newFixedThreadPool(2);
            Future<String>f1 = es1.submit(new ThreadPoolCallable());
            String s1 = f1.get();
            System.out.println(s1);
            //得到返回值,输出a
        }
    }

    简单应用:多线程异步计算

    使用两个线程计算求和:

    package demo1;
    
    import java.util.concurrent.Callable;
    
    public class GetSumCallable implements Callable<Integer> {
        private int a;
    
        public GetSumCallable(int a) {
            this.a = a;
        }
    
        public Integer call() {
            int sum = 0;
            for (int i = 0; i <= a; i++) {
                sum += i;
            }
            return sum;
        }
    }
    package demo1;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class ThreadPoolDemo {
        public static void main(String[] args) throws Exception {
            ExecutorService es1 = Executors.newFixedThreadPool(2);
            Future<Integer> f1 = es1.submit(new GetSumCallable(100));
            Future<Integer> f2 = es1.submit(new GetSumCallable(300));
            System.out.println(f1.get());
            System.out.println(f2.get());
            es1.shutdown();
        }
    }
  • 相关阅读:
    2020-2021-1 20209326 《Linux内核原理与分析》第八周作业
    2020-2021-1 20209326 《Linux内核原理与分析》第七周作业
    2020-2021-1 20209326 《Linux内核原理与分析》第六周作业
    2020-2021-1 20209326 《Linux内核原理与分析》第五周作业
    2020-2021-1 20209326 《Linux内核原理与分析》第四周作业
    2020-2021-1 20209326 《Linux内核原理与分析》第三周作业
    2020-2021-1 20209326 《Linux内核原理与分析》第二周作业 MyOD(选作)
    2020-2021-1 202029325 《Linux内核原理与分析》第十二周作业
    2020-2021-1 202029325 《Linux内核原理与分析》第十一周作业
    2020-2021-1 202029325 《Linux内核原理与分析》第九周作业
  • 原文地址:https://www.cnblogs.com/xuyiqing/p/8319833.html
Copyright © 2011-2022 走看看