创建线程
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的优点:
- 适合多个相同的程序代码的线程去共享同一个资源
- 可以避免 java 中的单继承的局限性。
- 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
- 实现了 Runable 接口的话,很容易的实现资源共享(一个实例多个线程运行)。
- 线程池只能放入实现 Runnable 或 Callable 类线程,不能直接放入继承 Thread 的类。
使用实现Runnable
接口的方式创建线程和通过继承Thread
类创建线程有以下几个区别:
- Java不支持多重继承。如果我们已经扩展了一个类,但是又想创建一个新的线程,那么使用
Runnable
接口实现方式会更加灵活,因为我们可以将该类实现Runnable
接口,而不必继承Thread
类。 - 使用
Runnable
接口实现方式可以更好地遵循单一职责原则。在这种方式下,我们可以将线程的实现和类的实现分离,从而使得类的代码更加简洁和清晰。 - 在使用
Runnable
接口实现方式时,多个线程可以共享同一个Runnable
实例。这使得我们可以更好地管理线程,因为我们可以在多个线程之间共享状态。而在继承Thread
类的方式中,每个线程都是独立的,这可能会导致一些线程之间的状态不一致问题。 - 当我们实现
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
接口,我们可以更好地管理线程,从而使得代码更加灵活和高效。