Java 教程 8:创建线程的两种方式和匿名类的使用

作者 : 慕源网 本文共4191个字,预计阅读时间需要11分钟 发布时间: 2022-04-15 共326人阅读

线程是计算机上的一个单独进程;您可以同时运行多个线程。CPU(中央处理器)实际处理这种情况的方式通常是在线程之间快速切换,以产生多个进程同时发生的假象,当然,如果您有多个CPU,您的计算机可以同时在两个CPU上运行代码。

正是您的计算机的这一功能允许您同时运行多个应用程序。

多线程代码的缺点是很快就会变得非常复杂,尽管Java有一些很好的类来处理多线程并简化它。

当多个线程需要访问相同的资源时,复杂性就会增加。让多个线程修改单个共享研究(数组或其他)可能会导致灾难,需要小心处理。

另一方面,您通常绝对需要多个线程——例如,在运行用户界面的同时监视端口或消息队列。

在本教程中,我们将只看创建线程,以及使用匿名类来简化(或者有些人会说,复杂化)您的代码。

强烈推荐

海量程序代码,编程资源,无论你是小白还是大神研究借鉴别人优秀的源码产品学习成熟的专业技术强势助力帮你提高技巧与技能。在此处获取,给你一个全面升级的机会。只有你更值钱,才能更赚钱

如果你是初级程序员可以研究别人的代码提高技术,如果你喜欢搞网盟或者外包,可以让你快速建站,还等什么赶快关注吧,我们会持续输出相关资源

海量源码程序,学习别人的产品设计思维与技术实践

Java中创建线程的两种方式

在Java中创建线程有两种方法。第一种方法是扩展Thread类,用要执行的代码覆盖run()方法,然后从类中创建一个新对象并调用start()。

第二种方法是将Runnable接口的实现传递给Thread的构造函数,然后调用start()。

我们将依次介绍这两种方法。

扩展Thread类

在下面的代码中,我们创建了一个扩展Thread的Worker类。我们重写了run()方法,并在其中加入了重复循环并输出一个方法。

我们还使用了Thread类的一个静态方法sleep()。您可以向sleep()传递几毫秒的睡眠时间,它会在您指定的时间内暂停当前线程的执行。

public class Worker extends Thread {

    @Override
    public void run() {
        
        // Loop for ten iterations.
        
        for(int i=0; i<10; i++) {
            System.out.println(i + " looping ...");
            
            // Sleep for a while
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                // Interrupted exception will occur if
                // the Worker object's interrupt() method
                // is called. interrupt() is inherited
                // from the Thread class.
                break;
            }
        }
    }

}

请注意,如果使用sleep(),则必须捕获InterruptedException。如果线程在睡眠时被中断,则会引发此异常。我们可以通过调用线程的interrupt()方法来中断线程。在我们这里的代码中,如果线程被中断,我们只需调用break。此关键字导致循环的执行停止。

在下面的代码中,我们创建了两个Worker类,并调用它们继承的start()方法。请注意,它们同时运行,而不是一个接一个地运行。

public class Application {

    
    public static void main(String[] args) {
        Worker worker1 = new Worker();
        worker1.start();
        
        Worker worker2 = new Worker();
        worker2.start();
        
        // You can call interrupt() if you want
        // to interrupt a thread. The thread itself
        // decides how to handle interrupts.
        // worker1.interrupt();
    }
    
}
0 looping ...
0 looping ...
1 looping ...
1 looping ...
2 looping ...
2 looping ...
3 looping ...
3 looping ...
4 looping ...
4 looping ...
5 looping ...
5 looping ...
6 looping ...
6 looping ...
7 looping ...
7 looping ...
8 looping ...
8 looping ...
9 looping ...
9 looping ...

从父线程类继承的start()方法创建一个新线程,并在新线程中运行run()中的任何代码。

当然,没有什么可以阻止我们自己直接调用run()方法,但是worker.run()方法在主程序线程中一个接一个地运行,而不是同时运行。

如何不使用线程:

public class Application {

    
    public static void main(String[] args) {


        Worker worker1 = new Worker();
        worker1.run();
        
        Worker worker2 = new Worker();
        worker2.run();
        
        // You can call interrupt() if you want
        // to interrupt a thread. The thread itself
        // decides how to handle interrupts.
        // worker1.interrupt();
    }
    
}
0 looping ...
1 looping ...
2 looping ...
3 looping ...
4 looping ...
5 looping ...
6 looping ...
7 looping ...
8 looping ...
9 looping ...
0 looping ...
1 looping ...
2 looping ...
3 looping ...
4 looping ...
5 looping ...
6 looping ...
7 looping ...
8 looping ...
9 looping ...
…当然,这段不使用多线程的代码需要两倍的运行时间。

将代码直接传递给线程

启动线程的第二种方法是将要运行的代码放在实现Runnable接口的类的Run方法中,然后将其传递给Thread类的构造函数。

下面的代码就是这样做的;我们将所有代码都放在一个文件中,以便更容易理解。

class CodeRunner implements Runnable {

    @Override
    public void run() {
        // Loop for ten iterations.
        
        for(int i=0; i<10; i++) {
            System.out.println(i + " looping ...");
            
            // Sleep for a while
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                break;
            }
        }       
    }
    
}

public class Application {

    
    public static void main(String[] args) {
        
        CodeRunner runner = new CodeRunner();
        
        Thread thread = new Thread(runner);
        thread.start();
    }
    
}
0 looping ...
1 looping ...
2 looping ...
3 looping ...
4 looping ...
5 looping ...
6 looping ...
7 looping ...
8 looping ...
9 looping ...

再一次,代码在它自己的线程中运行,我们可以在合理的范围内同时运行或多或少的CodeRunner实例。

我们可以通过直接在CodeRunner类上调用new来简化这段代码,就在我们创建线程的地方。

Thread thread = new Thread(new CodeRunner());
thread.start();

匿名类和线程

 

事实上,我们可以通过直接在线程构造函数中创建一个新的Runnable实例来使这段代码更加简洁。

实际上,我们不能创建Runnable的新实例,因为它是一个接口;所以我们不能做以下事情:

// Won't work
Thread thread = new Thread(new Runnable());
thread.start();
但是,如果我们添加一些花括号并在其中实现缺少的run()方法,我们就可以让它运行。
// This works
Thread thread = new Thread(new Runnable() {

    @Override
    public void run() {
                
    }
            
});
        
thread.start();

我们传递给thread()的对象的类到底是什么?它不是Runnable的实例;Runnable只是一个接口。它是一个没有名字的类的实例——一个匿名类——它实现了Runnable。

实际上,您可以对抽象类使用相同的技巧,也可以以相同的方式覆盖现有类的方法。

这种技术虽然看起来很奇怪,但在Java中经常使用。例如,不仅可以创建线程,还可以实现与Swing中的按钮相关联的操作。

当然,要让这段代码做任何事情,我们必须添加一些实际的代码来运行。

Thread thread = new Thread(new Runnable() {

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

thread.start();
0 looping ...
1 looping ...
2 looping ...
3 looping ...
4 looping ...
5 looping ...
6 looping ...
7 looping ...
8 looping ...
9 looping ...

最后,我们可以使代码更简洁,不需要声明一个变量来保存Thread类,然后直接调用start()方法。

new Thread(new Runnable() {

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

(我在这里删除了sleep(),只是为了让代码更清晰一点。您可能不想像这样将大量代码放入方法或构造函数调用中,但当您只需要调用一个或两个方法时,这通常很方便。


慕源网 » Java 教程 8:创建线程的两种方式和匿名类的使用

常见问题FAQ

程序仅供学习研究,请勿用于非法用途,不得违反国家法律,否则后果自负,一切法律责任与本站无关。
请仔细阅读以上条款再购买,拍下即代表同意条款并遵守约定,谢谢大家支持理解!

发表评论

开通VIP 享更多特权,建议使用QQ登录