一 程序、进程、线程
程序:
为完成某种特定功能,使用计算机语言编写一系列指令的集合,即静态代码。
进程:
正在执行的程序,是操作系统分配资源的最小单位。
线程:
进程内部的最小执行单元,是操作系统进行任务调度的最小单元
备注:
早期cpu执行是以进程为单位,后来cpu执行改为更小的线程为单位,一个程序内有多个线程,只需切换线程即可。
二 进程和线程的关系
1.一个进程中可以包含多个线程,线程必须属于某一个线程,不能独立存在。
2.一个进程中必须有一个主线程,但在主线程中可以创建其他子线程。
3.一个进程的所有线程可以共享该进程的所有资源。
三 Java如何创建线程
继承Thread类的方式:
1.在Java中要实现线程,最简单的方式就是扩展Thread类,重写其中的run方法。
2.Thread类中的run方法本身并不执行任何操作,如果我们重写了run方法,当线程启动时,它将执行 run方法。
定义:
public class c extends Thread{
@Override
public void run() {
}
}
调用:
public class c {
public static void main(String[] args) {
Thread thread = new Thread();
thread.start();
}
}
实现Runnable接口的方式:
1. java.lang.Runnable接口中仅仅只有一个抽象方法,
@Override
public void run() {
}
2.也可以通过实现Runnable接口的方式来实现线程,只需要实现其中的run方法即可。
3. Runnable接口的存在主要是为了解决Java中不允许多继承的问题。
区别:
继承Thread,由于Java是单继承的,所以就不能继承其他类了,实现Runnable接口的方式,可以继承其它类
四 Thread类中的方法
方法原型 | 说明 |
void start() | 启动线程 |
final String getName() | 返回线程的名称 |
final void setPriority(int newPriority) | 设置线程的优先级 |
final int getPriority() | 返回线程的优先级 |
final void join | 等待线程终止 |
static Thread currentThread() | 返回对当前正在执行的线程对象的引用 |
static void sleep(long millis) | 让当前正在执行的线程休眠(暂停执行), 休眠时间由milli s(毫秒)指定 |
yield() | 线程让步 |
五 线程状态
新建:
当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态。
new Thread()/new Thread的子类
就绪:
处于新建状态的线程被start()后,将进入线程队列等待CPU时 间片,此时它已具备了运行的条件,只是没分配到CPU资源。
Thread.start();
运行:
当就绪的线程被调度并获得CPU资源时,便进入运行状态,run()方法定义了线程的操作和功能。
@Override
public void run() {
}
阻塞:
在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU并临时中止自己的执行,进入阻塞状态。
Thread.sleep();
死亡:
线程完成了它的全部工作或线程被提前强制性地中止或出现异常导致结束。
六 守护线程
Java中的线程分为两类:用户线程和守护线程
public class DaemonThread extends Thread{
@Override
public void run() {
int i = 0;
while (true){
System.out.println("DaemonThread:"+i++);
}
}
}
public class Test {
public static void main(String[] args) {
DaemonThread daemonThread = new DaemonThread();
daemonThread.setDaemon(true);
daemonThread.start();
for (int i = 0; i <1000 ; i++) {
System.out.println("main:"+i);
}
}
}
七 多线程
定义:
只一个程序内部,可以创建多个线程执行不同的任务。
何时需要线程?
1.需执行多个功能时,例如:杀毒软件,QQ等。
2.程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、 网络操作、搜索等。
多线程的优点:
1.提高程序的响应。
2.提高cpu的利用率。
3.改善程序结构。
多线程的缺点:
1.占用内存。
2.占用cpu资源,需要对多线程进行管理。
3.多线程同时对共享资源进行访问,如果不加以控制就会产生安全问题。
多线程安全问题:
通过sycnhronized和lock把同代码块锁住防止多个线程同时访问同一个对象。
八 线程同步
并发:
在一个时间段内,多个任务依次执行。
并行:
真正意义上的同时执行,一个时间节点上有多个任务同时执行。
同步锁:
同步锁可以是任何对象,必须唯一,保证多个线程获得是同一个对象(用 来充当锁标记)。
同步执行过程:
1.第一个线程访问,锁定同步对象,执行其中代码。
2.第二个线程访问,发现同步对象被锁定,无法访问。
3.第一个线程访问完毕,解锁同步对象。
4.第二个线程访问,发现同步对象没有锁,然后锁定并访问。
synchronized关键字:
synchronized (同步锁){
// 需要被同步的代码;
}
public synchronized void show (String name){
// 需要被同步的代码;
}
九 LOCK
lock:
1.从JDK 5.0开始,Java提供了更强大的线程同步机制-通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当。
2.java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。
3.ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁。
lock和synchronized的区别:
1.实现原理不同:ReentranrLock是一种java代码层面的控制实现,而synchronized是关键字,依靠的底层编译后的指令实现。
2.加锁范围不同:ReentrantLock只能对一段代码块加锁,而synchronized可以对代码块和方法加锁。
3.加锁方式不同:ReentrantLock是手动加锁释放锁,而synchronized是隐式的自动加锁,自动释放锁。
十 线程通信
定义:
线程通讯指的是多个线程通过相互牵制,相互调度,即线程间的相互作用。
方法:
wait一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
notify一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个。
notifyAll一旦执行此方法,就会唤醒所有被wait的线程。
sleep和wait的区别:
sleep()让线程阻塞指定时间,时间到后,自己唤醒进入到就绪状态,不会释放同步锁,是Thread中的方法。
wait()让线程进入等待(阻塞),不会自己唤醒,必须通过notify(),notifyAll()唤醒,
等待时会释放同步锁,是Object类中的方法。