栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

多进程和多线程(Java)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

多进程和多线程(Java)

多进程和多线程(Java)

文章目录
    • 多进程和多线程(Java)
      • 1.什么是进程?什么是线程?
      • 2.进程和线程是什么关系?举个例子
      • 3.分析下列代码存在几个线程
      • 4.Java语言中,实现线程有两种方式,那两种方式呢?
        • 1.编写一个类,直接继承java.lang.Thread,重写run方法。
          • run和start的区别
          • Thread类的一些重要方法:
          • 上述方法是被 Thread 对象调用的,下面表格的方法是 Thread 类的静态方法。
        • 2.编写一个类,实现java.lang.Runnable接口,实现run方法。
      • 5.线程的生命周期
      • 6.获取线程名字
      • 7.获取当前线程对象
      • 8.线程的sleep
        • 小问题:下列代码中的sleep方法会让线程t进入休眠吗?
      • 9.终止线程休眠
      • 10.强行终止一个线程的执行
      • 11.合理终止一个线程的执行

1.什么是进程?什么是线程?

进程是一个应用程序(1个进程是一个软件)。
线程是一个进程中的执行场景/执行单元。
一个进程可以启动多个线程。

对于java程序来说,当在DOS命令窗口中输入:java HelloWorld 回车之后。会先启动JVM,而JVM就是一个进程。JVM再启动一个主线程调用main方法。同时再启动一个垃圾回收线程负责看护,回收垃圾。最起码,现在的java程序中至少有两个线程并发,一个是垃圾回收线程,一个是执行main方法的主线程。

2.进程和线程是什么关系?举个例子

阿里巴巴:进程
马云:阿里巴巴的一个线程
童文红:阿里巴巴的一个线程

京东:进程
强东:京东的一个线程
妹妹:京东的一个线程

进程可以看做是现实生活当中的公司。
线程可以看做是公司当中的某个员工。

注意:
进程A和进程B的内存独立不共享。(阿里巴巴和京东资源不会共享的!)
魔兽游戏是一个进程
酷狗音乐是一个进程
这两个进程是独立的,不共享资源。

​ 线程A和线程B呢?
​ 在java语言中:
​ 线程A和线程B,堆内存和方法区内存共享。
​ 但是栈内存独立,一个线程一个栈。

启动多个线程是多个栈,S1在压栈弹栈,S2也在压栈弹栈,S3也在压栈弹栈,S1 S2 S3同时齐头并进并发,S1不用管S2,S2不用管S3…这个就是多线程并发,堆和方法区只有一块,所以对于多线程来说,堆和方法区内存是共享的,但是栈内存是独立的

​ 假设启动10个线程,会有10个栈空间,每个栈和每个栈之间,
​ 互不干扰,各自执行各自的,这就是多线程并发。

​ 火车站,可以看做是一个进程。
​ 火车站中的每一个售票窗口可以看做是一个线程。
​ 我在窗口1购票,你可以在窗口2购票,你不需要等我,我也不需要等你。
​ 所以多线程并发可以提高效率。

​ java中之所以有多线程机制,目的就是为了提高程序的处理效率。

使用了多线程机制之后,main方法结束,是不是有可能程序也不会结束。main方法结束只是主线程结束了,主栈空了,其它的栈(线程)可能还在压栈弹栈。

3.分析下列代码存在几个线程
package JavaSE.Thread;

public class ThreadTest01 {
    public static void main(String[] args) {
        System.out.println("main begin");
        m1();
        System.out.println("main over");
    }

    private static void m1() {
        System.out.println("m1 begin");
        m2();
        System.out.println("m1 over");
    }

    private static void m2() {
        System.out.println("m2 begin");
        m3();
        System.out.println("m2 over");
    }

    private static void m3() {
        System.out.println("m3 execute");
    }
}

只有一个主线程,主栈,没有启动分支栈,没有启动分支线程,所有这段代码只有一个主线程

一个栈中,自上而下的顺序依次逐行执行

4.Java语言中,实现线程有两种方式,那两种方式呢?

java支持多线程机制。并且java已经将多线程实现了,我们只需要继承就行了。

1.编写一个类,直接继承java.lang.Thread,重写run方法。

创建一个新的类,该类继承 Thread 类,然后创建一个该类的实例。继承类必须重写 run() 方法,该方法是新线程的入口点。它也必须调用 start() 方法才能执行。该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一个实例。

package JavaSE.Thread;

public class ThreadTest02 {
    public static void main(String[] args) {
        //主线程,新建一个分支线程对象
        MyThread1 t = new MyThread1();
        //启动线程
        t.start();
        //run方法在分支栈的底部,main方法在主栈的底部,run和main是平级的
        for (int i = 0; i < 1000; i++) {
            System.out.println("主线程-->" + i);
        }
    }
}

class MyThread1 extends Thread {
    @Override
    public void run() {
        //编写程序,这段程序运行在分支线程(分支栈)中
        for (int i = 0; i < 1000; i++) {
            System.out.println("线程分支-->" + i);
        }
    }
}
run和start的区别

Thread类的一些重要方法:

public void start()
使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

public void run() 如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。

public final void setName(String name)
改变线程名称,使之与参数 name 相同。

public final void setPriority(int priority) 更改线程的优先级。

public final void setDaemon(boolean on) 将该线程标记为守护线程或用户线程。

public final void join(long millisec)
等待该线程终止的时间最长为 millis 毫秒。

public void interrupt()
中断线程。

public final boolean isAlive() 测试线程是否处于活动状态。

上述方法是被 Thread 对象调用的,下面表格的方法是 Thread 类的静态方法。

public static void yield()
暂停当前正在执行的线程对象,并执行其他线程。

public static void sleep(long millisec)
在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。

public static boolean holdsLock(Object x)
当且仅当当前线程在指定的对象上保持监视器锁时,才返回 true。

public static Thread currentThread()
返回对当前正在执行的线程对象的引用。

public static void dumpStack()
将当前线程的堆栈跟踪打印至标准错误流。

2.编写一个类,实现java.lang.Runnable接口,实现run方法。

创建一个线程,最简单的方法是创建一个实现 Runnable 接口的类。为了实现 Runnable,一个类只需要执行一个方法调用 run()

package JavaSE.Thread;

public class ThreadTest03 {
    public static void main(String[] args) {
        //创建一个可运行的对象
        MyRunnable1 r = new MyRunnable1();
        //将可运行的对象封装成一个线程对象
        Thread t = new Thread(r);
        //启动线程
        t.start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("主线程-->" + i);
        }
    }
}

class MyRunnable1 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("线程分支-->" + i);
        }
    }
}

注意:第二种方式实现接口比较常用,因为一个类实现了接口,它还可以去继承其它的类,更灵活。
但是,使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程

采用匿名内部类创建线程对象

package JavaSE.Thread;

public class ThreadTest04 {
    public static void main(String[] args) {
        //创建线程对象,采用匿名内部类
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    System.out.println("线程分支-->" + i);
                }
            }
        });

        //启动线程
        t.start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("主线程-->" + i);
        }
    }
}
5.线程的生命周期

6.获取线程名字
package JavaSE.Thread.SellTicket;

public class ThreadTest05 {
    public static void main(String[] args) {
        //创建线程对象
        MyThread2 t = new MyThread2();
        //设置线程名字
        t.setName("ttt");
        //获取线程名字
        System.out.println(t.getName());
        //如果不设置线程名字,默认是Thread-0,Thread-1...
    }
}

class MyThread2 extends Thread {
    @Override
    public void run() {
        //编写程序,这段程序运行在分支线程(分支栈)中
        for (int i = 0; i < 1000; i++) {
            System.out.println("线程分支-->" + i);
        }
    }
}
7.获取当前线程对象

Thread t=Thread.currentThread();//返回值t就是当前线程

package JavaSE.Thread.SellTicket;

public class ThreadTest05 {
    public static void main(String[] args) {
        //这个代码出现在main方法当中,所有这个线程就是主线程
        Thread tt = Thread.currentThread();//获取当前线程对象
        System.out.println(tt.getName());//主线程名字就叫main

        //创建线程对象
        MyThread2 t = new MyThread2();
        //设置线程名字
        t.setName("ttt");
        //获取线程名字
        System.out.println(t.getName());
        //如果不设置线程名字,默认是Thread-0,Thread-1...
//        t.start();
    }
}

class MyThread2 extends Thread {
    @Override
    public void run() {
        //currentThread就是当前线程对象
        Thread currentThread = Thread.currentThread();
        for (int i = 0; i < 1000; i++) {
            System.out.println(currentThread.getName() + "-->" + i);
        }
    }
}

8.线程的sleep

关于线程的sleep方法:static void sleep(long millis)

​ 1.静态方法:Thread.sleep(1000)

​ 2.参数是毫秒

​ 3.作用:让当前进程进入休眠,进入“阻塞状态”,放弃占有CPU时间片,让给其他线程

​ 这行代码出现在A线程中,A线程就进入休眠,出现在B线程中,B线程就进入休眠

package JavaSE.Thread;

public class ThreadTest06 {
    public static void main(String[] args) {
        //让当前线程进入休眠,休眠5秒
        try {
            Thread.sleep(1000 * 5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("hello world");//5秒后输出这行代码
    }
}
package JavaSE.Thread;

public class ThreadTest06 {
    public static void main(String[] args) {
//        //让当前线程进入休眠,休眠5秒
//        try {
//            Thread.sleep(1000 * 5);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        System.out.println("hello world");//5秒后输出这行代码
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "-->" + i);

            //睡眠一秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

小问题:下列代码中的sleep方法会让线程t进入休眠吗?
package JavaSE.Thread;

public class ThreadTest07 {
    public static void main(String[] args) {
        //创建线程对象
        Thread t = new MyThread3();
        t.setName("ttt");
        t.start();

        //调用sleep方法
        try {
            //问题:这行代码会让线程t进入休眠状态吗?
            t.sleep(1000 * 5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("HelloWorld");
    }
}

class MyThread3 extends Thread {
    public void run() {
        for (int i = 0; i < 10000; i++) {
            System.out.println(Thread.currentThread().getName() + "-->" + i);
        }
    }
}

答案是不会,这行代码的作用是让当前进程进入休眠,也就是说main线程进入休眠。所有HelloWorld 5秒后才输出

9.终止线程休眠

sleep休眠太久了,如果希望半道上醒来,怎么办?怎么叫醒一个正在休眠的线程?

注意:这个不是终止线程的执行,而是终止线程的休眠

package JavaSE.Thread;

public class ThreadTest08 {
    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable2());
        t.setName("tt");
        t.start();

        //希望5秒后,线程醒来
        try {
            Thread.sleep(1000 * 5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //终止t线程的休眠(这种终断休眠的方式依靠了Java的异常处理机制)
        t.interrupt();
    }
}

class MyRunnable2 implements Runnable {

    @Override
    public void run() {

        //run()方法当中的异常不能throws,只能try catch
        //因为run()方法在父类中没有抛出任何异常,子类重写不能抛出更多异常
        System.out.println(Thread.currentThread().getName() + "--> begin");
        try {
            Thread.sleep(1000 * 60 * 60 * 24 * 365);//休眠1年
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "--> end");
    }
}

10.强行终止一个线程的执行

在Java中如何强行终止一个线程的执行

package JavaSE.Thread;

public class ThreadTest09 {
    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable3());
        t.setName("tt");
        t.start();

        //模拟5秒睡眠
        try {
            Thread.sleep(1000 * 5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //5秒后,强行终止t线程
        t.stop();//已过时,不建议使用
        
    }
}

class MyRunnable3 implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "-->" + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

不建议使用stop() !!!

11.合理终止一个线程的执行
package JavaSE.Thread;

public class ThreadTest10 {
    public static void main(String[] args) {
        MyRunnable4 r = new MyRunnable4();
        Thread t = new Thread(r);
        t.setName("tt");
        t.start();

        //模拟5秒
        try {
            Thread.sleep(1000 * 5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //终止线程
        //你想要什么时候终止t,就把标记改为false就行了
        r.run = false;
    }
}

class MyRunnable4 implements Runnable {
    //打一个boolean标记
    boolean run = true;

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (run) {
                System.out.println(Thread.currentThread().getName() + "-->" + i);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                //return 就结束了,你在结束之前还有什么没保存的
                //在这里可以保存
                //save...
                //save...

                //终止当前线程
                return;
            }
        }
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/868519.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号