创建线程的三种方法

创建线程

1.通过继承Thread类来创建线程
public class MyThread extends Thread{
    
    public MyThread(String name){
        super(name);
    }
    @override
    public void run(){
        for(int i=0;i<10;i++){
            System.out.println(getName()+"线程"+i);
        }
    }
}

public class Main{
    public static void main(String []args){
        MyThread thread1 = new MyThread("mythread1");
        MyThread thread2 = new MyThread("mythread2");
        
        thread1.start();
        thread2.start();
    }
}

运行结果将会是mythread1和mythread2交替执行,线程的并发

2.通过实现Runnable来创建线程
public class MyThread1 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+i);
        }
    }
}

public class MyThread1Test {
    public static void main(String[] args) {
        MyThread1 runablethread1 = new MyThread1();
        MyThread1 runablethread2 = new MyThread1();


        Thread thread1 = new Thread(runablethread1,"线程一");
        Thread thread2 = new Thread(runablethread2,"线程二");

        thread1.start();
        thread2.start();

    }
}

在Java中,创建线程的一种常见方式是实现Runnable接口。Runnable接口是一个具有单个run()方法的函数式接口。该接口中的run()方法是需要在线程中执行的代码。

当我们实现Runnable接口时,我们必须覆盖run()方法,并在其中编写要在线程中执行的代码。然后我们可以将实现了Runnable接口的对象传递给一个Thread对象,并调用start()方法启动线程。这将导致Thread对象调用实现了Runnable接口的对象的run()方法,从而在新线程中执行该方法中的代码。

使用Runnable接口创建线程的优点是我们可以在同一个类中实现多个线程,而不必扩展Thread类。另外,由于Java不支持多重继承,这种方式可以让我们更灵活地继承其他类。

总之,实现Runnable接口是一种简单、灵活且常用的创建线程的方式,它能够帮助我们编写并发代码。

实现Runable接口和继承Thread类的区别

使用Runable的优点:

  1. 适合多个相同的程序代码的线程去共享同一个资源
  2. 可以避免 java 中的单继承的局限性。
  3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
  4. 实现了 Runable 接口的话,很容易的实现资源共享(一个实例多个线程运行)。
  5. 线程池只能放入实现 Runnable 或 Callable 类线程,不能直接放入继承 Thread 的类。

使用实现Runnable接口的方式创建线程和通过继承Thread类创建线程有以下几个区别:

  1. Java不支持多重继承。如果我们已经扩展了一个类,但是又想创建一个新的线程,那么使用Runnable接口实现方式会更加灵活,因为我们可以将该类实现Runnable接口,而不必继承Thread类。
  2. 使用Runnable接口实现方式可以更好地遵循单一职责原则。在这种方式下,我们可以将线程的实现和类的实现分离,从而使得类的代码更加简洁和清晰。
  3. 在使用Runnable接口实现方式时,多个线程可以共享同一个Runnable实例。这使得我们可以更好地管理线程,因为我们可以在多个线程之间共享状态。而在继承Thread类的方式中,每个线程都是独立的,这可能会导致一些线程之间的状态不一致问题。
  4. 当我们实现Runnable接口时,我们可以将实现了Runnable接口的对象传递给Thread构造函数,从而使得我们可以更好地控制线程的创建和启动。而在继承Thread类的方式中,线程的创建和启动是耦合在一起的,这可能会使得我们在编写代码时更加困难。

综上所述,使用实现Runnable接口的方式创建线程是一种更加灵活和可控的方式,它能够更好地遵循单一职责原则,更好地管理线程,并且在代码编写上更加简洁和清晰。

【举例】

下面是一个使用实现Runnable接口的方式避免了多重继承的例子:

假设我们有一个Person类和一个Worker类,我们想要创建一个WorkerThread类来表示一个执行工作的线程。我们可以使用实现Runnable接口的方式来实现这个类,而不必继承Thread类。

public class Person {
    private String name;

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

    public String getName() {
        return name;
    }
}

public class Worker {
    private String company;

    public Worker(String company) {
        this.company = company;
    }

    public String getCompany() {
        return company;
    }
}

public class WorkerThread implements Runnable {
    private Person person;
    private Worker worker;

    public WorkerThread(Person person, Worker worker) {
        this.person = person;
        this.worker = worker;
    }

    @Override
    public void run() {
        System.out.println(person.getName() + " is working at " + worker.getCompany());
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person("John");
        Worker worker = new Worker("Google");

        Thread thread = new Thread(new WorkerThread(person, worker));
        thread.start();
    }
}

在这个例子中,我们定义了一个Person类和一个Worker类,分别表示人和工人。我们还定义了一个WorkerThread类,它实现了Runnable接口。在WorkerThread类中,我们通过构造函数将一个Person对象和一个Worker对象传递给了类实例。在run()方法中,我们打印出Person对象的名称和Worker对象的公司名称。在Main类中,我们创建了一个Person对象和一个Worker对象,并将它们传递给一个WorkerThread对象,然后将该对象传递给一个Thread对象,从而启动一个线程。

通过这个例子,我们可以看到,使用实现Runnable接口的方式,我们可以更灵活地组合类和线程,而不必扩展Thread类。这使得我们可以避免多重继承的问题,并且使代码更加清晰和灵活。

3.通过实现Callable接口来创建线程
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class MyCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum += i;
        }
        return sum;
    }

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        MyCallable callable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(callable);

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

        int result = futureTask.get();
        System.out.println("Result: " + result);
    }
}

在这个例子中,我们定义了一个MyCallable类,它实现了Callable接口。在call()方法中,我们计算了1到100的和,然后返回结果。

main()方法中,我们创建了一个MyCallable对象,并将该对象传递给一个FutureTask对象。我们将FutureTask对象传递给一个Thread对象,然后启动线程。

我们调用futureTask.get()方法来等待线程执行完毕,并获取线程返回的结果。最后,我们将结果打印出来。

使用Callable接口和FutureTask类创建线程的优点是可以获得线程执行的返回结果,并且可以使用FutureTask类来管理和取消线程。但是,使用这种方式也需要更多的代码和处理。

futureTask.get()是一个用于获取线程执行结果的方法,该方法将阻塞当前线程直到线程执行完毕,并返回线程执行的结果。在上面的例子中,我们使用futureTask.get()方法获取线程执行的结果,并将结果打印出来。

需要注意的是,如果线程没有执行完毕,调用futureTask.get()方法会阻塞当前线程。因此,如果不想阻塞当前线程,可以使用isDone()方法来判断线程是否执行完毕,或者使用get(long timeout, TimeUnit unit)方法来设置超时时间。

在多线程编程中,通过使用FutureTask类和Callable接口,我们可以更好地管理线程,从而使得代码更加灵活和高效。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值