【多线程】多线程的作用及实例

多线程的几种实现方式

线程创建与运行

Java 中有三种线程创建方法,分别为实现 Runnable 接口的run方法、继承 Thread 类并重写 run 方法、使用 FutureTask 方式。

首先看下继承 Thread 方法的实现:

public class ThreadTest {

    //继承Thread类并重写run方法
    public static class MyThread extends Thread {

        @Override
        public void run() {

            System.out.println("I am a child thread");

        }
    }

    public static void main(String[] args) {

        // 创建线程
        MyThread thread = new MyThread();

        // 启动线程
        thread.start();
    }
}

如上代码 MyThread 类继承了 Thread 类,并重写了 run 方法,然后调用了线程的 start 方法启动了线程,当创建完 thread 对象后该线程并没有被启动执行.

当调用了 start 方法后才是真正启动了线程。其实当调用了 start 方法后线程并没有马上执行而是处于就绪状态,这个就绪状态是指该线程已经获取了除 CPU 资源外的其它资源,等获取 CPU 资源后才会真正处于运行状态。

当 run 方法执行完毕,该线程就处于终止状态了。使用继承方式好处是 run 方法内获取当前线程直接使用 this 就可以,无须使用 Thread.currentThread() 方法,不好的地方是 Java 不支持多继承,如果继承了 Thread 类那么就不能再继承其它类,另外任务与代码没有分离,当多个线程执行一样的任务时候需要多份任务代码,而 Runable 则没有这个限制,下面看下实现 Runnable 接口的 run 方法方式:

    public static class RunableTask implements Runnable{

        @Override
        public void run() {
            System.out.println("I am a child thread");
        }

    }
 public static void main(String[] args) throws InterruptedException{

        RunableTask task = new RunableTask();
        new Thread(task).start();
        new Thread(task).start();
}

如上面代码,两个线程公用一个 task 代码逻辑,需要的话 RunableTask 可以添加参数进行任务区分,另外 RunableTask 可以继承其他类,但是上面两种方法都有一个缺点就是任务没有返回值,下面看最后一种是使用 FutureTask:

//创任务类,类似Runable
public static class CallerTask implements Callable<String>{

        @Override
        public String call() throws Exception {

            return "hello";
        }

    }

    public static void main(String[] args) throws InterruptedException {
    // 创建异步任务
        FutureTask<String> futureTask  = new FutureTask<>(new CallerTask());
        //启动线程
        new Thread(futureTask).start();
        try {
           //等待任务执行完毕,并返回结果
            String result = futureTask.get();
            System.out.println(result);
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
}

注:每种方式都有自己的优缺点,应该根据实际场景进行选择。

更多内容详见https://gitchat.csdn.net/activity/5aa4d205c2ff6f2e120891dd?utm_source=so

多线程的作用

1.可以解决负载均衡问题,充分利用CPU的资源,为了提高Cpu的使用,采用多线程的方法去同时完成几件事情而互不干扰

2.大多数的情况下, 使用多线程 主要是需要处理大量的IO操作或处理的情况需要花大量的时间等

3.异步处理,将程序中占据时间长的任务放到后台去处理

好处:
1、使用线程可以把程序中占据时间长的任务放到后台去处理,如图片、视频的下载
2、发挥多核处理器的优势,并发执行让系统运行的更快、更流畅,用户体验更好
缺点:
1、大量的线程降低代码的可读性,
2、更多的线程需要更多的内存空间
3、当多个线程对同一个资源出现争夺的时候要注意线程安全的问题。

实例

1.异步处理

不使用线程:

package thread;
 
public class SleepTest {
    public static void main(String[] args) throws Exception {
        System.out.println("begin");
        Thread.sleep(5000);//模拟业务场景
        System.out.println("end");
    }
}

例子很简单,控制台输出begin并且在五秒后打印end

使用线程

package thread;
 
public class SleepTest {
    public static void main(String[] args) throws Exception {
        System.out.println("begin");
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);//模拟业务场景
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        System.out.println("end");
    }
}

效果,执行后控制台立刻显示begin和end
因为目前我们不需要中间处理的结果,因此可以让它在后台执行,不阻塞主线程。

另外,也可以使用线程池实现上面的功能,代码如下:

package thread;
 
import java.util.concurrent.Executors;
 
public class SleepTest {
    public static void main(String[] args) throws Exception {
        System.out.println("begin");
        Executors.newSingleThreadExecutor().submit(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);// 模拟业务场景
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        System.out.println("end");
    }
}

2.文件转pdf

package org.framework.core.extend.swftools;
 
import org.framework.core.util.FileUtils;
 
/**
 * 文件转换调用接口
 * 
 * @author mosesframe
 *
 */
public class SwfToolsUtil {
	public static void convert2SWF(final String inputFile) {
 
		new Thread("文件转化服务") {
			public void run() {
				String extend = FileUtils.getExtend(inputFile);
				PDFConverter pdfConverter = new OpenOfficePDFConverter();
				SWFConverter swfConverter = new SWFToolsSWFConverter();
				if (extend.equals("pdf")) {
					// swfConverter.convert2SWF(inputFile,extend);
					// 该项目这里注释掉,前台预览使用了pdf.js,因此不需要转换成swf文件了,避免浪费更多的时间
				}
				if (extend.equals("doc") || extend.equals("docx")
						|| extend.equals("xls") || extend.equals("pptx")
						|| extend.equals("xlsx") || extend.equals("ppt")
						|| extend.equals("txt") || extend.equals("odt")) {
					DocConverter converter = new DocConverter(pdfConverter,
							swfConverter);
					converter.convert(inputFile, extend);
				}
			}
		}.start();
 
	}
}

猜你喜欢

转载自blog.csdn.net/xiaren_1988/article/details/101451282