多线程

进程

每一个应用程序在运行时,都会产生至少一个进程(process)。

进程是操作系统进行“资源分配和调度”的独立单位。

Windows系统的“任务管理器”可以查看系统的进程,通过Ctrl+Shift+Esc组合键可以调出“任务管理器”。

进程具有三个特征:

  • 独立性:进程拥有自己独立的资源,有私有的地址空间。
  • 动态性:程序是静态的指令集合,而进程是活动的指令集合,进程有其生命周期。
  • 并发性:多个进程可以在同一个处理器上并发执行,互不影响。虽然同一时刻只能有一个进程执行,但是多个进程被快速轮换执行(时间片轮换算法),宏观上有同时执行的效果(同一时间段内执行)。

现代的操作系统都支持多进程并发执行。

线程

​ 线程(Thread)是执行特定任务的最小单位,是进程的执行单元,也被称为轻量级进程(Lightweight Process)。

​ 一个进程至少有一个线程,也可以有多个线程。所谓多线程就是指同一个进程可以同时并发处理多个任务。

​ 线程没有系统资源,多个线程共享其所属进程的系统资源,因此多线程运行时,需要处理好资源同步问题。

总结:

  • 操作系统可以同时执行多个任务,每个任务是一个进程;
  • 进程可以同时执行多个任务,每个任务是一个线程。

多线程的优点

多线程就是下图这种感觉:

对计算机来说,多线程可以提高CPU的利用率。

例如:网络的数据传输速率远低于计算机的处理能力,如果是单线程程序,在下载网络资源时,CPU需要花费大量的空闲时间来等待,而多线程能够利用这些空闲时间完成其他任务。

具体来说:

|--一个浏览器可以在下载的同时打开其他网页;

|--Web服务器可以同时相应多个用户请求;

|--QQ发送文件的时候还能跟其他人继续聊天……

当前线程

Thread.currentThread():获取当前线程

.getName():获取线程名称

public class TestMainThread {
public static void main(String[] args) {
// 获得当前运行的线程
Thread tMain = Thread.currentThread();
// 线程名称,优先级,线程组
System.out.println("当前运行的线程是:" + tMain);
System.out.println("线程名称:" + tMain.getName());
}
}

当前运行的线程是:Thread[main,5,main]

线程名称:main


创建线程

方法1:继承Thread类

Thread类代表线程,所有的线程对象都是Thread类或其子类的对象。

创建线程的步骤:

  1. 继承Thread类
  2. 重写run()方法(线程执行体)
  3. 创建Thread类的实例对象
  4. 调用start()方法启动线程

可以使用setName(…)为线程设置名字,用getName()获取。

默认情况下,主线程名为main,子线程名为Thread-0、Thread-1等。

public class _11NewThread {
public static void main(String[] args) {
Thread t1 = new MyT();
t1.setName("1");
t1.start();
Thread t2 = new MyT();
t2.setName(" 2");
t2.start();
}
}
class MyT extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("线程:" + super.getName());
}
}
}

方法2:实现Runnable接口

Runnable是个接口,实现Runnable接口的类还可以继承其它类,这是比方法1优越的地方。

  1. 实现Runable接口
  2. 重写run()方法
  3. 创建Runable对象
  4. 创建Thread对象
  5. 调用thread.start()方法,启动线程

实际创建的对象还是Thread实例。

public class _12NewThreadRunnable {
public static void main(String[] args) {
MyR r1 = new MyR("A");
Thread t1 = new Thread(r1);
t1.setName("XXX");
t1.start();
MyR r2 = new MyR(" B");
Thread t2 = new Thread(r2);
t2.start();
}
}
class MyR implements Runnable {
public MyR(String s) {
this.s = s;
}
private String s;
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("线程:" + s);
}
}
}

*方法3:实现Callable接口

使用Callable和FutureTask创建线程——可以获取线程的返回值。这种做法了解即可。

  1. 实现Callable接口的线程,需重写call()方法,有返回值
  2. 需要FutureTask类包装一下Callablle,该类实现了Runable接口
  3. 以Future对象为参数创建线程,调用start()方法启动
  4. 以Futrue对象.get()接收返回值
package ahjava.p06thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
// 实现Callable接口的线程,需重写call()方法,有返回值
// 需要FutureTask类包装一下Callablle,该类实现了Runable接口
// 以Future对象为参数创建线程,调用start()方法启动
// 以Futrue对象.get()接收返回值
public class _13NewThreadCallable {
public static void main(String[] args) {
MyCallable _Callable = new MyCallable("A");
FutureTask<String> _FutureTask = new FutureTask<>(_Callable);
Thread _Thread = new Thread(_FutureTask);
_Thread.start();
try {
// 模拟等待,此过程可看到子线程在执行
Thread.sleep(3000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
// 接受子线程的返回值
try {
String s = _FutureTask.get();
System.out.println("子线程的返回值 = " + s);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
class MyCallable implements Callable<String> {
public MyCallable(String s) {
this.s = s;
}
private String s;
@Override
public String call() throws Exception {
for (int i = 0; i < 100; i++) {
System.out.println("线程:" + s);
}
return "我是子线程,已经执行完毕";
}
}

start()和run()

调用start()是开启新线程,调用run()是普通方法调用。

方法调用是入栈操作,调用完毕则出栈。

如果直接调用run()方法,则是在原线程中进行方法调用,用的还是之原线程的栈。

调用start()才是开启一个新线程,会创建新的栈。


线程的优先级

最高 10 Thread.MAX_PRIORITY
默认 5 Thread.NORM_PRIORITY
最低 1 Thread.MIN_PRIORITY

演示示例:

Thread(Runnable target, String name):为线程直接命名

Thread.currentThread():获取当前线程

public class Priority线程优先级 {
// *可能不太容易看出来
public static void main(String[] args) {
MyRu r1 = new MyRu();
MyRu r2 = new MyRu();
MyRu r3 = new MyRu();
Thread t1 = new Thread(r1);
// 创建时命名
Thread t2 = new Thread(r2, " B");
Thread t3 = new Thread(r3);
t1.setName("A");
t3.setName(" C");
t1.setPriority(Thread.MAX_PRIORITY);
t3.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
t3.start();
}
}
class MyRu implements Runnable {
@Override
public void run() {
String sName = Thread.currentThread().getName();
int sPri = Thread.currentThread().getPriority();
for (int i = 0; i < 100; i++) {
System.out.println("线程:" + sName + " 优先级:" + sPri);
}
}
}

多线程的运行结果是不确定的,运行结果每次不同,可能有些时候看不出不同优先级的区别。

最新文章

  1. VS2015 调试Web项目 遭遇 HTTP 错误 500.23 - Internal Server Error
  2. Eclipse: 提示 Toolchain &quot;MinGW GCC&quot; is not detected
  3. Metasploit爆破tcpwrapped服务
  4. Delphi Berlin 10.1 for 小米平板2 (Win 10) 电子罗盘测试
  5. jQuery中的.bind()、.live()和.delegate()之间区别分析
  6. 一些有用的UtilityExtend小方法
  7. 【现代程序设计】【期末作业】【homework-09】
  8. LightOJ 1422 Halloween Costumes(记忆化搜索)
  9. 面试题:在O(1)时间删除链表结点
  10. Struts2-3.struts.xml的action可以简写
  11. [js高手之路] vue系列教程 - 实现留言板todolist(3)
  12. Linux 修改环境变量报错
  13. Linux系统编程---实现目录或者文件拷贝
  14. python基础学习(三)变量和类型
  15. swagger 指定字段不显示到文档里
  16. UVA 11796
  17. speex与webrtc回声消除小结
  18. 如何使用pycharm调试(debug) django的测试用例?
  19. 枚举Enum转换为List,获取枚举的描述
  20. Hibernate_day04--QBC查询

热门文章

  1. ES &amp; Filebeat 使用 Pipeline 处理日志中的 @timestamp
  2. python 作业 日报模板输出
  3. vue-cli中使用swiper
  4. Jmeter 用户定义的变量的使用
  5. K8S的Kafka监控(Prometheus+Grafana)
  6. [Luogu P3157][CQOI2011]动态逆序对 (树套树)
  7. 【Luogu】P1402 酒店之王 题解
  8. leetcode144add-two-numbers
  9. selenium-常用操作总结
  10. &lt;摘自&gt;飞:jxl简析[ http://www.emlog.net/fei ]