- 多线程的概述:即同时做多件事情;一个服务器可以让多个人同时访问。【资料获取】
- 进程的概述:在一个操作系统中,每个独立执行的程序都可称之为一个进程,也就是“正在运行的程序”。
- 在以上图示中,在一个程序中多个线程执行图,看似同时进行,其实是由CPU调度,CPU的运行速度很快,所以看起来像是同时执行的。
- 在Java中提供了实现多线程的两种方式:一种是继承java.lang包下的Thread类,覆写Thread类的run()方法,在run()方法中实现运行在线程上的代码;另一种是实现java.lang.Runnable接口,同样是在run()方法中实现运行在线程上的代码。
继承Thread类>
- 子类继承Thread类具有多线程能力。
- 启动线程:创建子类对象.start()。
- 具有oop单继承的局限性。
分析一下单线程和多线程的运行流程:
- 可以看出,单线程执行时会按照顺序一步步执行,而多线程,在main()方法和run()方法都可以同时运行。
- 线程开启不一定执行,由CPU调度执行。
public class TestThreadP1 extends Thread{
//继承Thread类
@Override
public void run() {
//重写run()方法
//run方法线程体:
for (int i = 0; i < 20; i++) {
System.out.println("run方法线程体" + i);
}
}
public static void main(String[] args) {
//创建一个线程对象:
TestThreadP1 thread = new TestThreadP1();
//调用start()方法,开启线程:
thread.start();
//主方法main线程:
for (int i = 0; i < 2000; i++) {
System.out.println("主方法main线程" + i);
}
}
}
注意:通过继承Thread类实现了多线程,但是这种方式有一定的局限性。因为Java中只支持单继承,一个类一旦继承了某个父类就无法再继承Thread类。
- 实现接口Runnable具有多线程能力,重写run()方法
- 启动线程:出入目标对象+Thread对象.start()
- 可以避免oop单继承的局限性,方便同一个对象被多个线程使用
与Thread不同,实现Runnable接口,可以解决Java单继承的问题,可以实现多线程,也可以继承于其他的类。
public class TestRunnable implements Runnable {
//实现Runnable接口
@Override
//run方法实现体:
public void run() {
for (int i = 0; i < 2000; i++) {
System.out.println("Runnable 执行!!!" + i);
}
}
public static void main(String[] args) {
//创建runnable接口的实现类:
TestRunnable test = new TestRunnable();
//创建线程对象,通过线程对象来开启线程:
Thread thread = new Thread(test);
//开启线程:
thread.start();
for (int i = 0; i < 20; i++) {
System.out.println("main 执行!!!" + i);
}
}
}
- 当多个线程同时操作同一个资源的情况下,线程不安全,会发生数据紊乱的情况。所以这时候,可以使用实现Callable接口来实现多线程;其可以抛出异常和定义返回值;这部分如果时初学者可以了解一下!到后期还是挺重要的。
- 重写call()方法,实现接口Callable具有多线程能力
- 创建执行服务(添加线程) ExecutorService
- 提交执行线程 (Future)
- 关闭线程 (shutdownNow)
- 可以定义返回值,可以抛出异常。
public class TestCallable implements Callable<Boolean> {
//实现Callable接口
private String url;
private String name;
public TestCallable(String url, String name) {
this.url = url;
this.name = name;
}
@Override
public Boolean call(){
WebDownload2 webdown = new WebDownload2();
webdown.downloader(url,name);
System.out.println("下载文件:" + name);
return true; //返回值
}
}
class WebDownload2{
public void downloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
//创建目标对象:
TestCallable t1 = new TestCallable("链接","名字");
TestCallable t2 = new TestCallable("链接","名字");
TestCallable t3 = new TestCallable("链接","名字");
//创建执行服务:
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行:
Future<Boolean> r1 = ser.submit(t1);
Future<Boolean> r2 = ser.submit(t2);
Future<Boolean> r3 = ser.submit(t3);
//关闭Callable服务
ser.shutdownNow();
}
}
- Java中Lambda表达式,虽然说时一种语法糖,但是在多线程中的作用还是非常大的。但是只有一点,如果想要使用Lambda表达式,这个方法必须时函数式接口,不然无法使用Lambda表达式。Lambda表达式的使用让定义函数式接口里的方法更加方便。
函数式接口的定义 - 任何接口,如果只包含唯一一个抽象方法,那么就是一个函数式接口。
- 对于函数式接口,可以通过lambda表达式来创建该接口的对象。
public class TestLambda {
public static void main(String[] args) {
Test test = new Testc();
test.run(100,"小明");
//Lambda表达式:
test = (a,b) -> {
//多个参数可以去掉参数类型,但是必须去掉括号
System.out.println(b + "run6--->" + a + "步");
};
test.run(10000,"小麦");
}
}
interface Test{
void run(int a, String b);