Java 线程讲解,这次没有人学不会了吧!!!
前言
不知道你们有没有想过,我们在打王者荣耀的时候,为什么可以那么多人同时一起打,可以相互能看到而互不影响,这个就和多线程有关,今天我们来学习线程。
线程
运行中的应用程序称为“进程”,进程中能够独立执行的控制流称为“线程”,一个进程可由多个线程组成,它们分别执行不同的任务,例如视频中同时可以听声音、看图像、看弹幕等。
进程是执行程序的一次执行过程,是动态的概念,是系统资源分配的单位;
线程是 CPU 调度和执行的单位,是独立的执行路径,一个进程中至少有一个线程,不然就没存在的意义。
注意:
真正的多线程是指有多个 CPU,也就是多核,很多多线程是模拟出来的。
线程的运行由调度器安排调度,调度器是与操作系统相关的,先后顺序是不能人为的干预;
线程会带来额外的开销,每个线程在自己的工作内存交互,内存控制不当会造成数据不一致;
线程的创建与启动
当用 Java 命令启动一个 JVM 进程时,JVM 会创建一个主线程,该线程从程序入口(main()方法)开始运行。
线程的创建有三种方式:继承 Thread 类、实现 Runnable 接口和实现 Callable 接口(简单了解)
其中 Thread 类的主要方法有:
start():启动线程;
currentThread():返回当前运行的 Thread 对象;
run():由调度程序调用,当 run()方法返回时,该线程停止;
sleep(int n):使线程睡眠 n 毫秒后,线程再次运行;
setPriority(int p):设置线程优先级;
getPriority():返回线程优先级;
yield():将 CPU 控制权主动移交到下一个可运行线程;
setName(String name):赋予线程一个名字;
getName():取得代表线程名字的字符串;
stop():停止线程的执行。
继承 java.lang.Thread 类
用户可以创建 Thread 类的实例来创建新的线程,它将与主线程并发运行。子类继承 Thread 类具备多线程能力,通过调用用户线程类的 start()方法即可启动用户线程。
创建步骤:
声明一个类并继承 Thread 类;
重写 run()方法,编写线程执行体;
创建线程对象并调用 start()方法启动线程。
例如:
运行结果为:
注意:
多次运行上述代码会发现,运行结果会不一样;
当运行的线程执行体很多时,会发现主线程和子线程会交替执行;
假如将 start()方法改为 run()方法,会根据代码顺序来执行,大家可以自行尝试试试。
实现 Runnable 接口
由于 Java 的单继承限制,有些类必须继承其他某个类同时又要实现线程的特性,这时可以通过实现接口 Runnable 来解决该问题。该接口具有多线程能力,启动线程为传入目标对象+Thread 对象.start()。创建一个线程来声明实现类 Runnable 接口,然后重写 run 方法。然后可分配类的实例,在创建 Thread 时作为参数传递并启动。
创建步骤:
定义类实现 Runnable 接口;
重写 run()方法,编写线程执行体;
创建线程对象;
创建 Thread 作为参数传递,调用 start()方法启动线程。
例如:
运行结果为:
注意:第 9、10 行代码可以改为:
实现 Callable 接口
由于 Callable 接口使用的很少,我们这里只做简单地了解该实现步骤,感兴趣的同学可以自行去编写代码实现。创建步骤:
实现 Callable 接口,需要返回值类型;
重写 call 方法,需要抛出异常;
创建目标对象;
创建执行服务:ExecutorService ser=Executors.newFixedThreadPool(1);
提交执行:Future<Boolean>result1=ser.submit(t1);
获取结果:boolean r1=result.get();
关闭服务器:ser.shutdownNow();
静态代理
代理这个词大家都不陌生吧,就是我帮你去做一件事情。例如我们在打王者荣耀的时候,有时会请别人帮自己上分,最后真正上分的账号是自己的账号。这种属于代理。
自己:属于真实角色;
代理角色:代理你,帮自己上分;
上分:实现都实现上分接口即可。
例如:
运行结果为:
注意:真实对象和代理对象都要实现同一个接口,代理对象要代理真实对象。
代理的好处:代理对象可以做很多真实对象做不了的事情,真实对象可以专注做自己的事情。
Lambda 表达式
为了避免匿名内部类定义过多,去掉了一些没有意义的代码,只留下核心的逻辑,让我们的代码看起来很简洁,我们可以使用 lambda 表达式。
注意:
lambda 表达式只能有一行代码的情况下才能简化成为一行,如果有多行,那么就用代码块包裹;
使用 Lambda 表达式的前提是接口为函数式接口。
函数式接口
任何接口,如果只包含唯一一个抽象方法,那么它就是是一个函数式接口,例如:
对于函数式接口,我们可以通过 Lambda 表达式来创建该接口的对象。
这样讲可能大家理解不了使用 Lambda 表达式的好处,我们现在通过两个例子来理解一下。
例子一:没有使用 Lambda 表达式
例子二:使用 Lambda 表达式
上面两个例子的代码的运行结果都一样,运行结果为:
Lambda 表达式可以继续简化,例子二中第 3 行代码可以简化为:
其运行结果不变。
注意:当有多个参数时,也可以去掉参数类型,但要所有参数类型都要去掉,参数必须要用括号括起来。
最后
好了,有关线程的一些知识讲到这里,谢谢观看!!!
下篇继续讲解线程的其他知识(线程的状态,线程的同步问题等等)
成功不是将来才有的,而是从决定去做的那一刻起,持续累积而成。
版权声明: 本文为 InfoQ 作者【霖~】的原创文章。
原文链接:【http://xie.infoq.cn/article/5e2b961ac91124c61899487e4】。文章转载请联系作者。
评论