Java拾贝第八天——多线程的创建

Java拾贝不建议作为0基础学习,都是本人想到什么写什么

进程与线程

多线程是实现并发机制的一种有效手段,进程和线程一样都属于并发的一个单位。(线程比进程更小)
所谓多线程是指一个进程在执行过程中可以产生多个线程。这些线程可能同时存在、同时运行。

一个进程可以包含一个或多个线程,但至少会有一个线程。

image
一般把一个任务称为一个进程,浏览器就是一个进程,视频播放器是另一个进程。

线程一般指程序的运行流程

多线程机制是指可以同时运行多个程序块。

线程的创建

在Java中创建线程一般有两种方式:继承Thread类,实现Runnable接口

继承Thread类

必须继承Thread类并重写run()方法。

public class Test8 {
    public static void main(String[] args) {
        MyThread m1 = new MyThread("线程m1");
        MyThread m2 = new MyThread("线程m2");
        m1.run();
        m2.run();
    }
}

class MyThread extends Thread {//继承Thread
    private String name;

    public MyThread(String name) {//构造方法
        this.name = name;
    }

    @Override
    public void run() {//重写run方法
        for (int i = 0; i < 10; i++) {
            System.out.println(this.name + "=" + i);
        }
    }
}

程序运行结果:

线程m1=0
线程m1=1
线程m1=2
线程m1=3
线程m1=4
线程m1=5
线程m1=6
线程m1=7
线程m1=8
线程m1=9
线程m2=0
线程m2=1
线程m2=2
线程m2=3
线程m2=4
线程m2=5
线程m2=6
线程m2=7
线程m2=8
线程m2=9

从结果上看并没有交错运行,因为线程实际上压根没有启动。

上述写法只是普通地实例化了一个对象并调用其run方法。

正确应该使用父类的Thread类的start()方法。

修改代码:

public class Test8 {
    public static void main(String[] args) {
        MyThread m1 = new MyThread("线程m1");
        MyThread m2 = new MyThread("线程m2");
        m1.start();//调用start()方法
        m2.start();
    }
}

class MyThread extends Thread {
    private String name;

    public MyThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {//run()就是线程执行的任务
        for (int i = 0; i < 10; i++) {
            System.out.println(this.name + "=" + i);
        }
    }
}

程序运行结果:

线程m2=0
线程m1=0
线程m2=1
线程m1=1
线程m2=2
线程m1=2
线程m2=3
线程m2=4
线程m2=5
线程m2=6
线程m2=7
线程m2=8
线程m2=9
线程m1=3
线程m1=4
线程m1=5
线程m1=6
线程m1=7
线程m1=8
线程m1=9

成功了!哪个线程对象抢到了CPU资源谁就运行。所以程序的每次运行结果肯定是不一样的。

如果一个线程对象多次调用start()方法,将会抛出IllegalThreadStateException异常。

    public static void main(String[] args) {
        Thread thread = new Thread() {//匿名内部类
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(i);
                }
            }
        };
        thread.start();
        thread.start();
    }

程序运行结果:

Exception in thread "main" java.lang.IllegalThreadStateException
	at java.lang.Thread.start(Thread.java:710)
	at moudle1.Test8.main(Test8.java:14)
0
1
2
3
4
5
6
7
8
9

实现Runnable接口

必须实现Runnable并重写run()方法。

但Runnable接口并没有提供默认的start(),那我们如何启动呢?

在Thread类中提供了构造方法,其传参就是Runnable接口的实现类

public Thread(Runnable target);
public class Test8 {
    public static void main(String[] args) {
        MyThread m1 = new MyThread("m1");
        MyThread m2 = new MyThread("m2");
        new Thread(m1).start();
        new Thread(m2).start();
    }
}

class MyThread implements Runnable {
    private String name;

    public MyThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(this.name + "=" + i);
        }
    }
}

程序运行结果:

m1=0
m2=0
m1=1
m2=1
m1=2
m2=2
m1=3
m2=3
m1=4
m2=4
m1=5
m2=5
m1=6
m2=6
m1=7
m2=7
m1=8
m2=8
m1=9
m2=9

从以上两种实现可以发现,无论使用哪种方式,最终都必须依靠Thread类才能启动线程。

注意:

    public static void main(String[] args) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类形式线程1");
            }
        }).start();

        System.out.println("main");

        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名内部类形式线程2");
            }
        }).start();
    }

程序运行结果:

main
匿名内部类形式线程1
匿名内部类形式线程2

虽然代码书写方式是从上至下的,但实际上这两个线程是平级并且不得知哪个线程优先启动。

image

posted @ 2023-10-21 20:26  rowbed  阅读(4)  评论(0编辑  收藏  举报