一、进程与线程
进程是操作系统的概念,是程序的一次执行过程,是系统运行程序的基本单位。我们运行的一个.exe就是一个进程。具体是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,即进程空间或(虚空间),一个进程中可以启动多个线程。
线程是依附于进程而存在的,是比进程更小的执行单元,可以理解为:进程中独立运行的子任务,每一个线程必须有进程。线程拥有自己的堆栈、程序计数器和局部变量,线程和其他的线程共享进程的系统资源。
进程不能共享内存,而线程之间可以轻松地共享内存。一个程序至少有一个进程,一个进程至少有一个线程。 另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
二、线程的创建
1、继承Thread类创建线程。定义Thread类的子类,并重写该类的run()方法,该方法的方法体就是线程需要完成的任务,run()方法也称为线程执行体。
2、实现java.lang.Runnable接口。void run() 使用实现接口Runnable的对象创建一个线程时,启动该线程将导致在独立执行的线程中调用对象的run方法。 方法run的常规协定是,它可能执行任何所需的操作。
实现 Runnable 接口
public class JueJin implements Runnable {
private String name;
public JueJin(String name) {
this.name = name;
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(name+"掘金"+i+"%");
}
}
public class ThreadTest {
public static void main(String[] args) {
Thread t = new Thread(new JueJin("抱枕"));
Thread t1 = new Thread(new JueJin("保温杯"));
t.start();
t1.start();
}
复制代码
继承 Thread 类
public class MyThread extends Thread {
private String name;
public MyThread(String name){
this.name = name;
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(name+"掘金"+i+"%");
}
}
public class ThreadTest {
public static void main(String[] args) {
//创建一个线程的对象
MyThread mt = new MyThread("抱枕");
//启动一个线程
mt.start();
//创建一个线程的对象
MyThread mt1 = new MyThread("保温杯");
//启动一个线程
mt1.start();
}
}
复制代码
三、线程的状态
线程一般具有5种状态,即新建,就绪,运行,阻塞,死亡。分别如下:
新建状态:在程序中用构造方法创建了一个线程对象后,新的线程对象便处于新建状态,此时它已经有了相应的内存空间和其他资源,但还处于不可运行状态。
就绪状态:新建线程对象后,调用该线程的start()方法就可以启动线程。当线程启动时,线程进入就绪状态。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu的使用权。
运行状态:当就绪状态被调用并获得处理器资源时,线程就进入了运行状态。线程获得CPU资源正在执行任务(run() 方法),此时除非此线程自动放弃 CPU 资源或者有优先级更高的线程进入,线程将一直运行到结束。
阻塞状态:一个正在执行的线程在某些特殊情况下,如被人为挂起或需要执行耗时的输入/输出操作,会让 CPU 暂时中止自己的执行,进入阻塞状态。发生阻塞时线程不能进入排队队列,只有当引起阻塞的原因被消除后,线程才可以转入就绪状态。阻塞的情况有三种: 调用 sleep(long t) 方法,可使线程进入睡眠方式。 一个睡眠着的线程在指定的时间过去可进入可运行(runnable)状态。
调用 wait() 方法。 调用 notify() 方法,回到就绪状态。
调用 suspend() 方法。 调用 resume() 方法,就可以恢复。
死亡状态:当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。 自然终止:正常运行完 run()方法,终止。 异常终止:调用 stop() 方法,让一个线程终止运行。
四.核心方法
sleep(long millis):线程休眠指定的时间,进入阻塞状态;
interrupt():切换线程为中断状态,抛出中断异常,不会停止线程,可以监视线程的中断状态并定义执行策略。
interrupted():清除调用该方法线程的中断状态,也不会影响线程的执行,且返回当前执行‘stopThread.interrupted()’的线程是否中断,这里就是指main线程是否中断。
isInterrupted():判断调用该方法的线程是否已经是中断状态。
使用Notify唤醒
public class WaitWithNotify {
public static void main(String[] args) {
Object lock=new Object();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock){
System.out.println(Thread.currentThread().getName()+"获取lock");
try {
System.out.println(Thread.currentThread().getName()+"调Wait()");
lock.wait();
System.out.println(Thread.currentThread().getName()+"再次获取lock");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
},"Thread1").start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (lock){
System.out.println(Thread.currentThread().getName()+"获得lock");
System.out.println(Thread.currentThread().getName()+"调Notify()");
lock.notify();
}
}
},"Thread2").start();
}
}
复制代码
定时唤醒
public class WaitWithTime {
public static void main(String[] args) {
Object lock=new Object();
new Thread(() -> {
synchronized (lock){
try {
System.out.println(Thread.currentThread().getName()+"获取lock");
System.out.println(Thread.currentThread().getName()+"waitting"+"currtime"+System.currentTimeMillis());
lock.wait(10000);
System.out.println(Thread.currentThread().getName()+"重新获取lock"+"currtime"+System.currentTimeMillis());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"Thread1").start();
}
}