我正在参与掘金创作者训练营第6期,点击了解活动详情
在并发的场景中实现线程是其中必须的,只有实现了多线程才可以进行一系列的操作。
创建线程
实现 Runnable 接口
创建类实现 Runnable 接口或者创建一个 Runnable 类的实例,并重写 run 方法。我的理解是该类相当于是一个任务,run 方法中是要执行的业务内容。所以要执行该任务必须将其放在 Thread 中并调用 start 方法才行。
public void example1(){
Runnable rn = new Runnable() {
@Override
public void run() {
System.out.println(" Runable 方法实现线程");
}
};
Thread th1 = new Thread(rn)
th1.start()
}
继承 Thread 类
创建类继承 Thread 类,然后创建该类的实例。继承类必须重写 run() 方法。然后调用start 方法才能执行。可以看到
public class ExtendsThread extends Thread {
@Override
public void run() {
System.out.println('用Thread类实现线程');
}
}
线程池创建线程
static class DefaultThreadFactory implements ThreadFactory {
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon()) t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
从上面线程池的源代码上可看大,线程池其实就是个线程工厂。其中创建线程的本质其实还是通过 new Thread() 创建线程的。其中增加了创建线程是的一些默认设置,如线程的名字、是否守护线程和线程优先级等。
有返回值的 Callable 创建线程
class CallableThread implements Callable<String>{
@Override
public String call() throws Exception{
return "Hello"
}
}
// 创建线程池
ExecutorService service = Executors.newFixedThreadPool(10);
Future<String> future = service.submit(new CallableThread());
Runnable 创建的线程是无返回值的,而 Callable 接口是带有返回值的。从以上源代码可以看出,CallableThread 其实也是一个任务,需要通过 submit方法将任务放在线程池中,并由线程池创建线程。
总结
个人认为:一个线程的创建其实就是 Thread 类, run() 方法其实就是线程中要执行的内容,然后通过 start 方法启动并创建该线程。通过实现 Runnable 接口的创建出来的类应该是一个可执行的线程任务内容,真正最要还是要放在线程里然后通过 start 方法启动该线程去执行该任务。
所以 start() 方法其实就是创建一个线程出来,一个线程只能一个 start() 方法,重写的 run() 方法里其实放的就是所需要执行的任务。run() 要被执行只有通过 start() 方法去启动线程然后才会调用 run() 方法。
通过实现 Runnable 接口方式创建的线程要比继承 Thread 类实现线程要好。
- Runnable 只有 run 方法,这样任务和线程 Thread 类 解耦。Runnable 负责定义要执行的内容,Thread 类负责线程启动和属性设置等内容,权责分明。
- Runnable 方法可以直接将任务传给线程池,而如果使用 thread ,每次执行任务都需要新建一个独立的线程,太浪费性能开销
- Java 不支持双继承,一旦继承了 Thread 类型,就会限制后续的扩展,扩展性低。