进程与线程
学习多线程,首先要知道什么是进程,什么是线程
①.进程:进程是一个执行的程序,指的是从代码加载、执行到执行结束的一个完整的过程。
②.多进程:计算机同时运行两个或者更多的程序。
③.线程:线程是比进程小的执行单位,一个进程可以通过运行多个线程来并发执行多项任务。
④.多线程:在单个程序中同时运行多个线程来完成不同的工作。
多线程概述
①.多线程是实现并发的一种有效手段,一个进程可以通过运行多个线程来并发地执行多项任务,而多个线程之间的调度执行,有系统来决定。
②.多个线程可以共享代码段、数据段和诸如打开的文件等的系统资源。
多线程的好处
①.线程共享相同的地址空间,提高CPU使用率。
②.线程共同分享同一个进程,提高应用程序的使用率。
③.由于同一个进程内的线程共享内存和文件,所以线程之间相互通信不必调用内核。
多线程的实现方式
Java的多线程机制提供了两种方式实现多线程变成,一种是通过继承Thread类来实现,一种是通过实现Runnable接口实现。
1.继承Thread类
①.重载该类的run()方法,把需要使用多线程运行的代码放入该方法。
②.创建线程对象并用该对象调用start()方法。
public class MyThread extends Thread {
@Override
public void run() {
for (int x = 0; x < 200; x++) {
System.out.println(x);
}
}
}
2.实现runnable接口
①.实现run()方法,把需要使用多线程运行的代码放入该方法。
②.runnable中只有一个run()方法,没有提供任何东西来支持多线程,所以它必须通过Thread类的框架实现多线程。
③.通过Thread类的构造函数,public Thread(Runnable target)来实现。
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int x = 0; x < 100; x++) {
// 由于实现接口的方式就不能直接使用Thread类的方法了,但是可以间接的使用
System.out.println(Thread.currentThread().getName() + ":" + x);
}
}
}
3.为什么定义这两种方式实现多线程
Java不支持多继承,所以如果用户的类已经继承了一个类,而有需要多线程机制的支持,此时继承Thread类就不现实了。所以Runnable接口在这种情况下就很实用。
4.run()与start()的区别
①.run(),仅仅封装了代码,直接调用为普通方法。
②.start(),会初始化一些和线程有关的资源,而后会调用run()方法。
线程的调度和优先级
1.线程的调度
①.分时调度
②.抢占式调度(Java采用的就是该调度模式)
2.线程的优先级
①.默认优先级是5
②.优先级的范围是0—10。可通过getPriority()方法来获取线程的优先级,通过setPriority()来设置线程的优先级。
线程的常用方法
①.void start() 使该线程开始执行;Java 虚拟机调用该线程的 run 方法
②.String getName() 返回该线程的名称。
③.void setName(String name) 改变线程名称,使之与参数 name 相同。
线程的控制
①.void interrupt() 中断线程。
②.void join() 等待该线程终止。
③.void setDaemon(boolean on) 将该线程标记为守护线程或用户线程。
④.static void sleep(long millis) 在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)。
⑤.static void yield() 暂停当前正在执行的线程对象,并执行其他线程。
线程的生命周期
多线程的安全问题
1.判断依据
①.是否有多线程环境
②.是否有共享数据
③.是否有多条语句操作共享数据
2.解决的思想
把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能执行。
线程的同步
1.同步的定义
①.所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回,同时其他线程也不同调用这个方法。
②.同步解决的是共享资源冲突的问题。
2.同步的用法
①.Java语言提供两个基本的同步用法:同步方法和同步语句(同步代码块)。
线程的死锁问题
死锁问题出现在同步嵌套中,线程不结束就不会释放锁,出现相互等待的情况。
public class DieLock extends Thread {
private boolean flag;
public DieLock(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if (flag) {
synchronized (MyLock.objA) {
System.out.println("if objA");
synchronized (MyLock.objB) {
System.out.println("if objB");
}
}
} else {
synchronized (MyLock.objB) {
System.out.println("else objB");
synchronized (MyLock.objA) {
System.out.println("else objA");
}
}
}
}
}
线程间通信问题
1.定义
线程间通信是指不同种类的线程间,对同一种资源操作。
2.方式
①.基本方式
②.同步机制:不同种类线程都加锁,必须是同一把锁。
③.等待唤醒机制(依次执行):加入flag标记,加入wait()方法,加入notify()方法。
注意:wait()自动释放锁,醒来时原地起步。并且wait()之后不抢执行权。
public class Student {
private String name;
private int age;
private boolean flag; // 默认情况是没有数据,如果是true,说明有数据
public synchronized void set(String name, int age) {
// 如果有数据,就等待
if (this.flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 设置数据
this.name = name;
this.age = age;
// 修改标记
this.flag = true;
this.notify();
}
public synchronized void get() {
// 如果没有数据,就等待
if (!this.flag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 获取数据
System.out.println(this.name + "---" + this.age);
// 修改标记
this.flag = false;
this.notify();
}
}