一、进程与线程
为什么要使用多线程?
当我们需要我们的PC同时进行听歌、玩游戏以及下载电影等,要怎么怎么办呢?这时我们就需要用多线程来解决这个问题。
进程(Process)
每个独立运行着的程序称为一个进程,也就是跑动的程序。
进程是操作系统分配资源的基本单位,有独立的内存空间和资源。
线程(Thread)
线程是一个进程内部的一条执行路径(path),Java虚拟机允许应用程序并发地运行多个执行路径。
并发:从宏观上看是同时运行,但从微观上看是同一时刻只能运行一个
并行:在微观上是同时运行(在多核情况下)
线程是进程中执行运算的最小单位,由处理机给线程,即真正在处理机上运行的是线程。
进程与线程的区别:
1、进程有独立的地址空间,一个进程崩溃后,不会对其它进程产生影响,而线程只是一个进程中的一个执行路径,如果有一条线程崩溃了,可能会影响同进程中的其他的线程。
2、进程有自己的栈和局部变量,多个线程共享同一进程的地址空间。
3、一个进程至少有一个线程。
多线程
多线程就是在一个进程中创建多个线程,每个线程完成一个任务
优点:
1、多线程技术使程序的响应速度更快
2、提高资源利用率
3、程序设计更简单
多线程执行特性
1、随机性(异步执行):谁“抢”到cpu,谁执行
2、宏观上同时执行,微观上同一时刻只能执行一个线程(多核除外)
二、线程的创建和启动
两种创建新线程的方式
第一种方式是:将类声明为Thred的子类并重写run()方法
@Override
class MyThread extends Thread{
public void run(){
线程具体执行的代码
}
}
创建此线程类的实例并启动:
MyThread thread1 = new MyThread();
thread1.start();//启动线程
线程的基本使用方法
public void start() //使该线程开始执行
public static Thread currentThread() //返回对当前正在执行的线程对象的引用
public final String getName() //返回该线程的名称
public final void setName(String name) //改变线程名称
public final void setDaemon(boolean on) //将该线程标记为守护线程或用户线程
public static void sleep(long millis) //线程休眠指定为毫秒时间
public final void join() //当前线程必须等待,直到调用join()方法的线程对象所对应的线程运行完毕,当前线程才能恢复执行
public static void yield() //线程礼让,但操作系统可以忽略这个礼让请求
三、线程的声明周期(状态转换)
线程的状态:创建、就绪、运行、阻塞、终止
线程的停止:
1、如果线程的run()方法中执行的是一个重复执行的循环,可以提供一个标记来控制循环是否执行;
2、如果线程因为执行sleep()或是wait()而进入了阻塞状态,此时想要停止它,可以使用interrupt(),程序会抛出InterruptException异常;
3、如果程序因为输入/输出的等待而阻塞,基本上必须等待输入/输出的动作完成才能离开阻塞状态。无法用interrupt()方法来使得线程离开run()方法,要想离开,只能引发一个异常。
第二种方式是:通过实现Runnable接口创建线程
定义实现Runnable接口的类
Runnable接口中只有一个方法public void run();用来定义线程运行体:
class MyRun implements Runnable{
public void run(){
线程执行的具体代码
}
}
创建线程的实例的时候将这个类的实例作为参数传递到线程实例内部,然后在启动:
Thread thread1 = new Thread(new MyRun);
thread1.start();
使用Runnable接口实现线程的优势:
优势一:
避免了Java单继承的局限性,实现了Runnable接口的类还可以继承另一个类或实现其他接口。
优势二:
使用实现Runnable接口的方式创建线程时可以为相同程序代码的多个线程提供共享的数据(资源共享)。
线程的创建与启动实例:
将类声明为Thred的子类并重写run()方法创建子线程
package thread;
public class MyThread extends Thread{
public MyThread() {
}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for(int i = 1; i < 10; i++) {
if(i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + "正在执行,i=" + i);
}
}
}
}
package thread;
public class ThreadDemo {
public static void main(String[] args) {
MyThread t1 = new MyThread("线程A");//实例化线程对象
t1.start();
MyThread t2 = new MyThread("线程B");
t2.start();
System.out.println("*********" + Thread.currentThread().getName() + "正在运行...*********");
}
}
运行结果:
Join方法实例:
package thread;
public class MyThread extends Thread{
public MyThread() {
}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for(int i = 1; i < 10; i++) {
if(i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + "正在执行,i=" + i);
}
}
}
}
package thread;
public class JoinMethod {
public static void main(String[] args) {
MyThread mt = new MyThread("我的线程");
mt.start();
for(int i = 0; i <= 10; i++) {
if(i == 4) {
try {
mt.join();//当前线程必须等待,直到调用join()方法的
//线程对象所对应的线程运行完毕,当前线程才能恢复执行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "执行,i=" + i);
}
}
}
运行结果:
Yield方法实例:
package thread;
public class JoinMethod {
public static void main(String[] args) {
MyThread mt = new MyThread("我的线程");
mt.start();
for(int i = 0; i <= 10; i++) {
if(i == 4) {
try {
mt.join();//当前线程必须等待,直到调用join()方法的
//线程对象所对应的线程运行完毕,当前线程才能恢复执行
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "执行,i=" + i);
}
}
}
package thread;
public class YieldMethod {
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.start();
for(int i = 0; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + "正在运行,i=" + i);
Thread.yield();//给调度程序的一个提示,当前程序愿意放弃它当前的处理器的使用
//调度程序可以自由的忽略这个提示
}
}
}
运行结果:
通过实现Runnable接口创建线程
package runnable;
/**
* 通过实现Runnable接口的方式创建线程
*/
public class MyRunnable implements Runnable {
@Override
public void run() {
for(int i = 1; i <= 10; i++) {
if(i % 2 == 0) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "输出偶数,i=" + i);
}
}
}
}
package runnable;
public class TestRunnable {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t = new Thread(mr,"子线程");//实例化一个线程对象,将Runnable的对象传入
t.start();//启动子线程
System.out.println(Thread.currentThread().getName() + "线程运行完毕...");
}
}
运行结果:
将当前线程设为守护线程的运行结果: