Java线程之创建线程
翻译自:https://www.journaldev.com/1016/java-thread-example
进程
进程是一个自包含的执行环境,它可以被看成一个程序或应用程序。然而一个应用程序本身包含多个进程,Java运行时环境作为一个单独的进程运行,它包含不同的类和程序
线程
线程可以成为轻量级进程,一个进程包含很多线程,线程占用很少的资源在进程中创建和运行,线程共享进程的资源
每个应用程序至少包含一个线程——主线程(main thread)。尽管有很多其他的java线程在后台运行,比如内存管理、系统管理、信号处理等等。但是从应用程序的角度来看——主线程是第一个java线程,我们可以从主线程中创建多个线程。
多线程是指在单个程序中同时执行的两个或多个线程。一个计算机单核处理器只能一次执行一个线程,而时间切片是在不同进程和线程之间共享处理器时间的操作系统特性。
Java线程的好处
- 与进程相比,Java线程是轻量级的,创建线程需要更少的时间和资源。
- 线程共享其父进程数据和代码,线程之间的上下文切换通常比进程之间的开销要小,线程间通信相对于进程通信来说是相对容易的
- Java提供了两种以编程方式创建线程的方法,实现java.lang.Runnable接口或继承java.lang.Thread类
线程实例
Java 线程 – 实现Runnable接口
为了使类可运行,我们可以实现java.lang。Runnable接口,并在public void.run()方法中提供实现。要将这个类用作线程,我们需要通过传递这个runnable类的对象创建一个线程对象,然后调用start()方法在一个单独的线程中执行run()方法
下面是一个实现Runnable接口的java线程示例:
package com.lkf.mulithread;
public class WorkRunnable implements Runnable {
@Override
public void run() {
System.out.println("Doing WorkRunnable processing - START " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
doSomething();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Doing WorkRunnable processing - END " + Thread.currentThread().getName());
}
private void doSomething() throws InterruptedException {
System.out.println("WorkRunnable do something");
Thread.sleep(2000);
System.out.println("WorkRunnable sleep 2000 millis");
}
}
Java 线程 – 继承 Thread 类
我们可以继承 java.lang.Thread 类创建我们自己的线程类并且覆盖 run() 方法。然后我们可以创建它的对象并调用 start() 方法,启动线程执行我们自定义的方法
下面是继承 Thread 类创建线程的实例:
package com.lkf.mulithread;
public class WorkExtendThread extends Thread {
public WorkExtendThread(String name) {
super(name);
}
@Override
public void run() {
System.out.println("WorkExtendThread - START " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
doSomething();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("WorkExtendThread - END " + Thread.currentThread().getName());
}
private void doSomething() throws InterruptedException {
System.out.println("WorkRunnable do something");
Thread.sleep(2000);
System.out.println("WorkRunnable sleep 2000 millis");
}
}
下面是一个展示如何创建java线程并执行它的测试程序:
package com.lkf.mulithread;
public class ThreadRunExample {
public static void main(String[] args) {
Thread implRunnableThread1 = new Thread(new WorkRunnable(), "ImplRunnableThread1");
Thread implRunnableThread2 = new Thread(new WorkRunnable(), "ImplRunnableThread2");
System.out.println("Starting ImplRunnableThread threads");
implRunnableThread1.start();
implRunnableThread2.start();
System.out.println("Runnable ImplRunnableThread has been started");
Thread workExtendThread3 = new WorkExtendThread("WorkExtendThread3");
Thread workExtendThread4 = new WorkExtendThread("WorkExtendThread4");
System.out.println("ExtendThreads MyThreads");
workExtendThread3.start();
workExtendThread4.start();
System.out.println("ExtendThreads has been started");
}
}
运行结果如下:
Starting ImplRunnableThread threads
Doing WorkRunnable processing - START ImplRunnableThread1
Doing WorkRunnable processing - START ImplRunnableThread2
Runnable ImplRunnableThread has been started
ExtendThreads MyThreads
WorkExtendThread - START WorkExtendThread3
WorkExtendThread - START WorkExtendThread4
ExtendThreads has been started
WorkRunnable do something
WorkExtendThread do something
WorkExtendThread do something
WorkRunnable do something
WorkRunnable sleep 2000 millis
WorkExtendThread sleep 2000 millis
Doing WorkRunnable processing - END ImplRunnableThread1
WorkExtendThread - END WorkExtendThread4
WorkRunnable sleep 2000 millis
WorkExtendThread sleep 2000 millis
Doing WorkRunnable processing - END ImplRunnableThread2
WorkExtendThread - END WorkExtendThread3
一旦我们启动了任何线程,它的执行依赖于时间切片的OS实现,我们无法控制它们的执行。但是,我们可以设置线程优先级,但即使这样,它也不能保证优先执行更高的优先级线程。
Runnable vs Thread
如果您的类提供了更多的功能,而不是仅仅作为线程运行,那么您应该实现Runnable接口,以提供一种将其作为线程运行的方法。 如果你只是希望创建一个可执行的线程,则可以继承Thread类。
实现Runnable是首选,因为java支持实现多个接口。如果继承Thread类,则不能继承其他类。
提示:您已经注意到,线程没有返回任何值,但是如果我们希望我们的线程执行一些处理,然后将结果返回给我们的客户端程序,那我们可以使用Java Callable Future,后面会另起篇幅说明。
更新:从Java 8开始,Runnable是一个功能接口,我们可以使用lambda表达式来提供它的实现,而不是使用匿名类。有关更多细节,将在使用Java 8功能接口中说明。