千家信息网

Java线程创建方式有哪些

发表于:2025-02-02 作者:千家信息网编辑
千家信息网最后更新 2025年02月02日,这篇文章给大家介绍Java线程创建方式有哪些,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。多线程的创建,方式一:继承于Thread类1.创建一个继承于Thread类的子类2.重写
千家信息网最后更新 2025年02月02日Java线程创建方式有哪些

这篇文章给大家介绍Java线程创建方式有哪些,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

多线程的创建,方式一:继承于Thread类

1.创建一个继承于Thread类的子类

2.重写Thread类的run()--->将此线程执行的操作声明在run()中

3.创建Thread类的子类的对象

4.通过此对象调用start():

start()方法的两个作用:

A.启动当前线程

B.调用当前线程的run()

创建过程中的两个问题:

问题一:我们不能通过直接调用run()的方式启动线程

问题二:在启动一个线程,遍历偶数,不可以让已经start()的线程去执行,会报异常;正确的方式是重新创建一个线程的对象。

//1.创建一个继承于Thread类的子类class MyThread extends Thread{    //2.重写Thread类的run()    @Override    public void run() {//第二个线程       for(int i = 0;i < 10;i++){           if(i % 2 == 0){               System.out.println(i);           }       }    }}public class ThreadTest {    public static void main(String[] args) {//主线程        //3.创建Thread类的子类的对象        MyThread t1 = new MyThread();        //4.通过此对象调用start()        t1.start();        //问题一:不能通过直接调用run()的方式启动线程//        t1.run();//错误的        //问题二:再启动一个线程:我们需要再创建 一个对象        //t1.start();//错误的        MyThread t2 = new MyThread();        t2.start();         for(int i = 0;i < 10;i++){            if(i % 2 != 0){                System.out.println(i + "****main()******");            }        }    }}

此代码在主线程内输出奇数,在另一个线程里输出偶数,则输出结果应该是两个输出结果是交互的。

1****main()******
3****main()******
5****main()******
7****main()******
0
2
4
6
8
9****main()******

class Window extends Thread{//创建三个窗口卖票, 总票数为100张,使用继承于Thread类的方式    private static int ticket = 100;//三个窗口共享:声明为static    @Override    public void run() {        while(true){            if(ticket > 0){                System.out.println(getName() + ":卖票,票号为:" + ticket);                ticket--;            }else{                break;            }        }    }}public class WindowTest2 {    public static void main(String[] args) {        Window t1 = new Window();        Window t2 = new Window();        Window t3 = new Window();        t1.setName("窗口1");        t2.setName("窗口2");        t3.setName("窗口3");        t1.start();        t2.start();        t3.start();    }}
public class ThreadDemo {    public static void main(String[] args) {//        MyThread1 m1 = new MyThread1();//        MyThread2 m2 = new MyThread2();//        m1.start();//        m2.start();        //由于造的类只创建过一次对象,后面就不用了,可以考虑使用匿名类的方式        //创建Thread类的匿名子类的方式        new Thread(){            @Override            public void run() {                for(int i = 0;i < 100;i++){                    if(i % 2 == 0){                        System.out.println(i);                    }                }            }        }.start();        new Thread(){            @Override            public void run() {                for(int i = 0;i < 100;i++){                    if(i % 2 != 0){                        System.out.println(i);                    }                }            }        }.start();    }}class MyThread1 extends Thread{    @Override    public void run() {        for(int i = 0;i < 100;i++){            if(i % 2 == 0){                System.out.println(i);            }        }    }}class MyThread2 extends Thread{    @Override    public void run() {        for(int i = 0;i < 100;i++){            if(i % 2 != 0){                System.out.println(i);            }        }    }}

创建多线程的方式二:实现Runnable接口

  • 创建一个实现了Runnable接口的类

  • 实现类去实现Runnable中的抽象方法:run()

  • 创建实现类的对象

  • 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象

  • 通过Thread类的对象调用start()

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():A.启动线程B.调用当前线程的run()-->调用了Runnable类型的target        t1.start();        //再启动一个线程,遍历100以内的偶数//只需重新实现步骤4,5即可        Thread t2 = new Thread(mThread);        t2.setName("线程2");        t2.start();    }}
class window1 implements Runnable{//创建三个窗口卖票, 总票数为100张,使用实现Runnable接口的方式    private int ticket = 100;    Object obj = new Object();    @Override    public void run() {        while (true){            if (ticket > 0) {                System.out.println(Thread.currentThread().getName() + "卖票,票号为:" + ticket);                ticket--;            } else {                break;            }        }    }}public class WindowTest {    public static void main(String[] args) {        window1 w = new window1();//只造了一个对象,所以100张票共享        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();    }}

创建线程的方式三:实现Callable接口---JDK5.0新增

与使用Runnable相比,Callable功能更强大些

>相比run()方法,可以有返回值

>方法可以抛出异常

>支持泛型的返回值

>需要借助FutureTask类,比如获取返回结果

Future接口

>可以对具体Runnable、Callable任务的执行结果进行取消、查询是否完成、获取结果等。

>FutureTask是Futrue接口的唯一的实现类

>FutureTaskb同时实现了Runnable,Future接口。它既可以作为Runnable被线程执行,又可以作为Future得到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;//sum是int,自动装箱为Integer(Object的子类)    }}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 {            //获取Callable中call()的返回值(不是必须的步骤)            //get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值。            Object sum = futureTask.get();            System.out.println("总和为:" + sum);        } catch (InterruptedException e) {            e.printStackTrace();        } catch (ExecutionException e) {            e.printStackTrace();        }    }}

创建线程的方式四:使用线程池--->JDK5.0新增

背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。

思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。

好处:>提高响应速度(减少了创建新线程的时间)

>降低资源消耗(重复利用线程池中线程,不需要每次都创建)

>便于线程管理:A.corePoolSize:核心池的大小 B.maximumPoolSize:最大线程数 C.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();    }}

比较创建线程的两种方式:

开发中:优先选择:实现Runnable接口的方式
原因:1.实现的方式没有类的单继承性的局限性
2.实现的方式更适合来处理多个线程有共享数据的情况。
系:public class Thread implements Runnable
相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()中

程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。

进程(process)是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生、存在和消亡的过程。---生命周期

线程(thread),进程可进一步细化为线程,是一个程序内部的一条执行路径。

线程作为调度和执行的单位,每个线程拥有独立的运行栈和计数器,每个进程拥有独立的方法区和堆;意味着,多个线程共享一个方法区和堆。而共享的就可以优化,同时,共享的也会带来安全隐患,这就需要我们解决线程安全问题

背景:以单核CPU为例,只使用单个线程先后完成多个任务(调用多个方法),肯定比用多个线程来完成用的时间更短,为何仍需使用多线程呢?

使用多线程的优点:

1.提高应用程序的响应。对图形化界面更有意义,可增强用户体验。

2.提高计算机系统CPU的利用率

3.改善程序结构。将即长又复杂的线程分为多个线程,独立运行,利于理解和修改

何时需要多线程

1.程序需要同时执行两个或多个任务。

2.程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等。

3.需要一些后台运行的程序时。

public class Sample{    public void method1(String str){        System.out.println(str);    }    public void method2(String str){        method1(str);    }    public static void main(String[] args){        Sample s = new Sample();        s.method2("hello!");    }}

注意:此程序不是多线程!main方法中调用了method1,method1中又调用了method2;是一条执行路径,所以是单线程

测试Thread类的常用方法:

1.start():启动当前线程:调用当前线程的run()
2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
3.currentThread():静态方法,返回执行当前代码的线程
4.getName():获取当前线程的名字
5.setName():设置当前线程的名字
6.yield():释放当前CPU的执行权(下一刻CPU执行的线程仍是随机的)
>暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程
>若队列中没有同优先级的线程,忽略此方法
7.join():在线程a中调用线程b的join(),此时,线程a就进入阻塞状态(停止执行),直到线程b完全执行完以后,线程b才结束阻塞状态(开始执行)。
8.sleep(long millitime):让当前线程"睡眠"指定的millitime毫秒。在指定的millitime毫秒时间内,当前线程是阻塞状态。会抛出InterruptedException异常
* 9.isAlive():判断当前线程是否存活

class HelloThread extends Thread{    @Override    public void run() {        for(int i = 0;i < 100;i++){            if(i % 2 != 0){                try {                    sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }                System.out.println(Thread.currentThread().getName() + ":" +Thread.currentThread().getPriority() + ":" + i);            }        }    }    public HelloThread(String name){        super(name);    }}public class ThreadMethodTest {    public static void main(String[] args) {        HelloThread h2 = new HelloThread("Thread:1");//通过构造器给线程命名,但前期是得在子类中提供一个构造器//        h2.setName("线程一");        //设置分线程的优先级        h2.setPriority(Thread.MAX_PRIORITY);        h2.start();        //给主线程命名        Thread.currentThread().setName("主线程");        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);        for(int i = 0;i < 100;i++){            if(i % 2 == 0) {                System.out.println(Thread.currentThread().getName() + ":" + Thread.currentThread().getPriority() + ":" + i);            }//            if(i == 20){//                try {//                    h2.join();//join()的测试//                } catch (InterruptedException e) {//                    e.printStackTrace();//                }//            }        }    }}

线程的优先级:

1.MAX_PRIORITY:10
MIN_PRIORITY:1
NORM_PRIORITY:5--->默认优先级
2.如何获取和设置当前线程的优先级:
getPriority():获取线程的优先级
setPriority(int p):设置线程的优先级
说明:高优先级的线程要抢占低优先级线程CPU的执行权,但是只是从概率上讲,高优先级的线程高概率的情况下,不一定被执行,并不意味着只有当高优先级的线程执行完毕后,低优先级的线程才执行。

关于Java线程创建方式有哪些就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

0