首页 > 编程语言 >Java多线程总结(超详细总结)

Java多线程总结(超详细总结)

时间:2023-08-04 13:37:00浏览次数:41  
标签:总结 Runnable run Thread start 线程 new Java 多线程

(Java多线程总结)

1.创建线程的方式

方式1

继承于Thread类

  1. 创建一个继承于Thread类的子类
  2. 重写Thread类的run() --> 将此线程执行的操作声明在run()中
  3. 创建Thread类的子类的对象 4. 通过此对象调用start() 例子:遍历100以内的所有的偶数
class MyThread extends Thread {
    //2. 重写Thread类的run()
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}


public class ThreadTest {
    public static void main(String[] args) {
        //3. 创建Thread类的子类的对象
        MyThread t1 = new MyThread();

        //4.通过此对象调用start():①启动当前线程 ② 调用当前线程的run()
        t1.start();
        //问题一:我们不能通过直接调用run()的方式启动线程。
//        t1.run();

        //问题二:再启动一个线程,遍历100以内的偶数。不可以还让已经start()的线程去执行。会报IllegalThreadStateException
//        t1.start();
        //我们需要重新创建一个线程的对象
        MyThread t2 = new MyThread();
        t2.start();


        //如下操作仍然是在main线程中执行的。
        for (int i = 0; i < 100; i++) {
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i + "***********main()************");
            }
        }
    }

}

方式2

实现Runnable接口

  1. 创建一个实现了Runnable接口的类
  2. 实现类去实现Runnable中的抽象方法:run()
  3. 创建实现类的对象
  4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
  5. 通过Thread类的对象调用start() 比较创建线程的两种方式。 开发中:优先选择:实现Runnable接口的方式 原因:1. 实现的方式没有类的单继承性的局限性 2. 实现的方式更适合来处理多个线程有共享数据的情况。 联系:public class Thread implements Runnable 相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中。
//1. 创建一个实现了Runnable接口的类
class MThread implements Runnable{

    //2. 实现类去实现Runnable中的抽象方法:run()
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }

        }
    }
}


public class ThreadTest1 {
    public static void main(String[] args) {
        //3. 创建实现类的对象
        MThread mThread = new MThread();
        //4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
        Thread t1 = new Thread(mThread);
        t1.setName("线程1");
        //5. 通过Thread类的对象调用start():① 启动线程 ②调用当前线程的run()-->调用了Runnable类型的target的run()
        t1.start();

        //再启动一个线程,遍历100以内的偶数
        Thread t2 = new Thread(mThread);
        t2.setName("线程2");
        t2.start();
    }

}

方式3

实现Callable接口。

--- JDK 5.0新增 如何理解实现Callable接口的方式创建多线程比实现Runnable接口创建多线程方式强大? 1. call()可以有返回值的。 2. call()可以抛出异常,被外面的操作捕获,获取异常的信息 3. Callable是支持泛型的

//1.创建一个实现Callable的实现类
class NumThread implements Callable{
    //2.实现call方法,将此线程需要执行的操作声明在call()中
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            if(i % 2 == 0){
                System.out.println(i);
                sum += i;
            }
        }
        return sum;
    }
}


public class ThreadNew {
    public static void main(String[] args) {
        //3.创建Callable接口实现类的对象
        NumThread numThread = new NumThread();
        //4.将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象
        FutureTask futureTask = new FutureTask(numThread);
        //5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
        new Thread(futureTask).start();

        try {
            //6.获取Callable中call方法的返回值
            //get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值。
            Object sum = futureTask.get();
            System.out.println("总和为:" + sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

}

方式4

使用线程池

好处: 1.提高响应速度(减少了创建新线程的时间) 2.降低资源消耗(重复利用线程池中线程,不需要每次都创建) 3.便于线程管理 corePoolSize:核心池的大小 maximumPoolSize:最大线程数 keepAliveTime:线程没有任务时最多保持多长时间后会终止 **

面试题:创建多线程有几种方式?四种

class NumberThread implements Runnable{

    @Override
    public void run() {
        for(int i = 0;i <= 100;i++){
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ": " + i);
            }
        }
    }
}

class NumberThread1 implements Runnable{

    @Override
    public void run() {
        for(int i = 0;i <= 100;i++){
            if(i % 2 != 0){
                System.out.println(Thread.currentThread().getName() + ": " + i);
            }
        }
    }
}

public class ThreadPool {

    public static void main(String[] args) {
        //1. 提供指定线程数量的线程池
        ExecutorService service = Executors.newFixedThreadPool(10);
        ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
        //设置线程池的属性
//        System.out.println(service.getClass());
//        service1.setCorePoolSize(15);
//        service1.setKeepAliveTime();


        //2.执行指定的线程的操作。需要提供实现Runnable接口或Callable接口实现类的对象
        service.execute(new NumberThread());//适合适用于Runnable
        service.execute(new NumberThread1());//适合适用于Runnable

//        service.submit(Callable callable);//适合使用于Callable
        //3.关闭连接池
        service.shutdown();
    }

}

2.线程安全

引出线程安全(卖票例子)

例子:创建三个窗口卖票,总票数为100张.使用实现Runnable接口的方式

1.问题:卖票过程中,出现了重票、错票 -->出现了线程的安全问题 2.问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票。 3.如何解决:当一个线程a在操作ticket的时候,其他线程不能参与进来。直到线程a操作完ticket时,其他 线程才可以开始操作ticket。这种情况即使线程a出现了阻塞,也不能被改变。

解决方式

在Java中,我们通过同步机制,来解决线程的安全问题。

方式一

在Java中,我们通过同步机制,来解决线程的安全问题。 方式一:同步代码块 synchronized(同步监视器){ //需要被同步的代码 } 说明: 1.操作共享数据的代码,即为需要被同步的代码。 -->不能包含代码多了,也不能包含代码少了。 2.共享数据:多个线程共同操作的变量。比如:ticket就是共享数据。 3.同步监视器,俗称:锁。任何一个类的对象,都可以充当锁。 要求:多个线程必须要共用同一把锁。 补充:在实现Runnable接口创建多线程的方式中,我们可以考虑使用this充当同步监视器。

class Window1 implements Runnable{

    private int ticket = 100;
//    Object obj = new Object();
//    Dog dog = new Dog();
    @Override
    public void run() {
//        Object obj = new Object();
        while(true){
            synchronized (this){//此时的this:唯一的Window1的对象   //方式二:synchronized (dog) {

                if (ticket > 0) {

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + ticket);


                    ticket--;
                } else {
                    break;
                }
            }
        }
    }
}


public class WindowTest1 {
    public static void main(String[] args) {
        Window1 w = new Window1();

        Thread t1 = new Thread(w);
        Thread t2 = new Thread(w);
        Thread t3 = new Thread(w);

        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();
    }

}


class Dog{

}

方式二

同步方法。 如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。 同步的方式,解决了线程的安全问题。---好处 操作同步代码时,只能有一个线程参与,其他线程等待。相当于是一个单线程的过程,效率低。 ---局限性

使用同步方法解决实现Runnable接口的线程安全问题 关于同步方法的总结: 1. 同步方法仍然涉及到同步监视器,只是不需要我们显式的声明。 2. 非静态的同步方法,同步监视器是:this 静态的同步方法,同步监视器是:当前类本身

class Window2 extends Thread{


    private static int ticket = 100;

    private static Object obj = new Object();

    @Override
    public void run() {

        while(true){
            //正确的
//            synchronized (obj){
            synchronized (Window2.class){//Class clazz = Window2.class,Window2.class只会加载一次
                //错误的方式:this代表着t1,t2,t3三个对象
//              synchronized (this){

                if(ticket > 0){

                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(getName() + ":卖票,票号为:" + ticket);
                    ticket--;
                }else{
                    break;
                }
            }

        }

    }
}


public class WindowTest2 {
    public static void main(String[] args) {
        Window2 t1 = new Window2();
        Window2 t2 = new Window2();
        Window2 t3 = new Window2();


        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");

        t1.start();
        t2.start();
        t3.start();

    }
}

标签:总结,Runnable,run,Thread,start,线程,new,Java,多线程
From: https://blog.51cto.com/u_16200113/6960270

相关文章

  • 无语!Jenkins 也宣布弃用 Java 8(文末送书)
    继Java之父JamesGosling先前称,开发者应尽快弃用JDK8,可以选择JDK17LTS,因为后者在各个方面都带来了巨大的改进。开源Devops工具Jenkins宣布:从6月28日发布的Jenkins2.357和即将发布的9月LTS版本开始,Jenkins最低需要Java11。Jenkins最初称为Hudson,是一款......
  • Java 大神整理的 Spring 笔记,强得起飞 !
    强烈推荐大家阅读:阿里大佬的spring学习笔记,基本涵盖了Spring所有核心知识点及原理,建议大家至少看3遍,便可成为一个Spring高手,超越99%的人,学完之后再去学Spring的其他框架,比如SpringBoot,简直就是小意思,文末获取高清pdfJava程序员加餐福利:小咖最近整理一份BAT面试资料,覆盖了Java核心......
  • 成为优秀Java开发者,需要看这几本书
    Java作为企业级应用开发的首选,深受互联网大厂的青睐。对于求职找工作的朋友来说,Java可能仍然是后端工程师的优选,虽然Python热度不断上升,但是Java作为老牌语言,在企业中的地位依旧稳固,它的市场空间仍然是很难撼动的。不同级别的IT从业者之间的工资差别非常大,相信每位程序员都不甘心只......
  • 差分约束总结
    差分约束是一个简单的能解一种特殊的\(n\)元一次不等式组(或者判断无解)的算法,其中每个不等式形如\(x_a-x_b\lec\),\(c\)是常数。差分约束利用了最短路的一个性质:一个有向图跑完最短路后一定满足对于任意一条边\((x,y,z)\),有\(dis_y\ledis_x+z\)这个性质很简单,因为既然......
  • java 用PDFBox 删除 PDF文件中的某一页
    依赖:org.apache.pdfboxpdfbox-app1.8.10java用PDFBox删除PDF文件中的某一页,前n页,后n页,效率低,不推荐使用packagecom.everjiankang;importjava.io.File;importorg.apache.pdfbox.pdmodel.PDDocument;/**运行效率很慢,因为每次删除一页就读取和保存一次文件,初始文件名格式:xxx......
  • Java中如何向一个string类型的数组中添加数据
    在Java中,String类型的数组是固定长度的,一旦创建后就无法改变其长度。如果你需要向一个String类型的数组中添加数据,可以考虑使用ArrayList或LinkedList等可变长度的集合类型来代替。使用 ArrayList,你可以通过调用add()方法来向集合中添加元素,例如://创建一个ArrayList......
  • java锁总结
    Java中的锁主要用于保障多并发线程情况下数据的一致性。在多线程编程中为了保障数据的一致性,我们通常需要在使用对象或者方法之前加锁,这时如果有其他线程也需要使用该对象或者该方法,则首先要获得锁,如果某个线程发现锁正在被其他线程使用,就会进入阻塞队列等待锁的释放,直到其他线程......
  • 为了成为Java大牛,我决定手写个JVM~
    JVM对我们很多人来说就像个黑盒子,无从下手,但是又是我们JavaCoder不得不去深入研究的一门技术国内玩JVM的大牛很少,知名的就那么几个,而玩好JVM又教好JVM的人更是少之又少。今天给大家介绍其中一位,江湖人送外号道格牙的子牙老师。下面的时间,交给他。哈喽,我就是江湖人送外号[......
  • 反内卷 | Java程序员不可错过的10本书!
    大家好,我是飘渺。又到了一年一度的双11了,想必不少小伙伴打算趁此机会入手几本好书。在此我也为大家整理了一份书单,如果你还在纠结犹豫,不妨看看我为整理的这几本。PS:今年京东的图书活动大致如下:活动一“多买优惠”,即:1件7.5折,两件6.5折活动二:“满减”,即:每满100-50这两个活动结算的时......
  • 【技术总结】大数据开发模块化知识体系、学习路线及对应的资料推荐
    〇、概述1、常用网站 2、常用学习路线图极客时间:石墨文档:https://shimo.im/docs/anJWOliiPz0WEjY0/read 大数据课程大纲:https://w.1yb.co/LEAzlvV【即石墨文档】 马士兵教育:https://www.processon.com/view/link/6244466b5653bb072bcd241d#map 尚硅谷:http://www.atguigu.com/......