JAVA线程的创建方法
Java多线程编程
Java 给多线程编程提供了内置的支持。 一条线程指的是进程中一个单一顺序
的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
以单核CPU为例,只使用单个线程先后完成多个任务(调用多个方法),
肯定比用多个线程来完成用的时间更短,为何仍需多线程呢?
多线程程序的优点:
- 提高应用程序的响应。对图形化界面更有意义,可增强用户体验;
- 提高计算机系统CPU的利用率;
- 改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改;
何时需要使用多线程
- 程序需要同时执行两个或多个任务;
- 程序需要实现- -些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等;
- 需要一些后台运行的程序时;
Java提供了三种创建线程的方法
- 通过继承 Thread 类本身;
- 通过实现 Runnable 接口;
- 通过 Callable 和 Future 创建线程;
创建方式(1)
一Thread一
- 创建一个继承于Thread类的子类;
- 重写Thread类的run() -->将此线程执行的操作声明在run()中;
- 创建Thread类的子类的对象;
- 通过此对象调用start();
package threadDemo02;
public class MyThread extends Thread{
@Override
public void run(){
for (int i = 0; i < 30; i++) {
System.out.println("MyThread类继承Thread输出结果第"+i+"遍");
}
}
}
package threadDemo02;
public class TestThread {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start();
for (int i = 0; i < 20; i++) {
System.out.println("这是主线程输出的第"+i+"遍");
}
}
}
创建方式(2)
一Runnable一
- 创建一个实现Runnable接口的类;
- 实现run方法(在方法当中写多线程需要执行的代码);
- 将实现Runnable接口的类以参数形式构造Thread类;
- 最后使用Thread对象调用start()方法启动;
class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo( String name) {
threadName = name;
System.out.println("在这里创建 " + threadName );
}
public void run() {
System.out.println("执行" + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("线程 " + threadName + ", " + i);
}
}catch (InterruptedException e) {
System.out.println("线程 " + threadName + " 执行中断.");
}
System.out.println("线程 " + threadName + " 不再执行.");
}
public void start () {
System.out.println("开始执行 " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo( "线程-1");
R1.start();
RunnableDemo R2 = new RunnableDemo( "线程-2");
R2.start();
}
}
创建方式(3)
一Callable一
- 创建Callable接口的实现类,并实现call()方法,然后创建该实现类的实例(从java8开始可以直接使用Lambda表达式创建Callable对象);
- 使用FutureTask类来包装Callable对象,该FutureTask对象封装了Callable对象的call()方法的返回值;
- 使用FutureTask对象作为Thread对象的target创建并启动线程;
- 调用FutureTask对象的get()方法来获得子线程执行结束后的返回值;
public class CallableThreadTest implements Callable<Integer> {
public static void main(String[] args)
{
CallableThreadTest c1 = new CallableThreadTest();
FutureTask<Integer> f1 = new FutureTask<>(c1);
for(int i = 0;i < 100;i++)
{
System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);
if(i==20)
{
new Thread(ft,"有返回值的线程").start();
}
}
try
{
System.out.println("子线程的返回值:"+f1.get());
} catch (InterruptedException e)
{
e.printStackTrace();
} catch (ExecutionException e)
{
e.printStackTrace();
}
}
@Override
public Integer call() throws Exception
{
int i = 0;
for(;i<100;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
}
return i;
}
}
三种方式的对比
-
采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。
-
使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。
多线程的使用
-
有效利用多线程的关键是理解程序是并发执行而不是串行执行的。例如:程序中有两个子系统需要并发执行,这时候就需要利用多线程编程。
-
通过对多线程的使用,可以编写出非常高效的程序。不过请注意,如果你创建太多的线程,程序执行的效率实际上是降低了,而不是提升了。
请记住,上下文的切换开销也很重要,如果你创建了太多的线程, CPU花费在上下文的切换的时间将多于执行程序的时间!!!