进程与线程
进程:执行中的程序,一个进程至少包括一个线程
线程:进程负责程序执行的执行单元,线程本身靠程序进行运行,线程时程序中的顺序控制流,只能使用分配给程序的资源和环境
线程与进程一样分为五个阶段:
- 创建:新创建了一个线程对象
- 就绪:线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权
- 运行:就绪状态的线程获取了CPU,执行程序代码
- 阻塞:阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
- 等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中(wait会释放持有的锁)
- 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中
- 其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态(注意,sleep是不会释放持有的锁)
- 终止:线程执行完了或者因异常退出了run()方法,该线程结束生命周期
多进程是指操作系统中能同时运行多个任务(程序)。
多线程是指同一程序中有多个顺序流在执行。
Java中实现多线程的方法
- 继承Thread类
- 实现Runnale接口
Thread类
public class ThreadTest {
public static void main(String[] args) {
MissionA a = new MissionA();
MissionB b = new MissionB();
a.start();
b.start();
}
}
class MissionA extends Thread{
@Override
public void run() {
for(int i =0;i<10;i++){
System.out.println(getName()+":"+i);
try {
Thread.sleep(100);//休眠,在休眠状态的线程不会得到执行,当指定时间过后,线程会重新处于就绪状态
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MissionB extends Thread{
@Override
public void run() {
for(int i =10;i<20;i++){
System.out.println(getName()+":"+i);
}
}
}
Runnale接口
public class RunnableTest {
public static void main(String[] args) {
Mission m = new Mission();
Thread t = new Thread(m);
t.start();
}
}
class Mission implements Runnable{
@Override
public void run() {
for(int i=0;i<10;i++){
Thread t = Thread.currentThread();
System.out.println(t.getName()+":"+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Thread和Runnable的区别
Runnable的优势
- 适合多个相同的程序代码的线程去处理同一个资源
- 可以避免java中的单继承的限制
- 增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
- 线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
线程的优先级
Java线程有优先级,优先级高的线程会获得较多的运行机会
Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级。
每个线程都有默认的优先级。主线程的默认优先级为Thread.NORM_PRIORITY。
线程的优先级有继承关系,比如A线程中创建了B线程,那么B将和A具有相同的优先级。
JVM提供了10个线程优先级,但与常见的操作系统都不能很好的映射。如果希望程序能移植到各个操作系统中,应该仅仅使用Thread类有以下三个静态常量(MAX_PRIORITY 、MIN_PRIORITY 、 NORM_PRIORITY )作为优先级,这样能保证同样的优先级采用了同样的调度方式。
线程睡眠:Thread.sleep(long millis)方法,使线程转到阻塞状态。millis参数设定睡眠的时间,以毫秒为单位。当睡眠结束后,就转为就绪(Runnable)状态。sleep()平台移植性好。
线程等待
Object类中的wait()方法,导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 唤醒方法。这个两个唤醒方法也是Object类中的方法,行为等价于调用 wait(0) 一样。
线程让步
Thread.yield() 方法,暂停当前正在执行的线程对象,把执行机会让给相同或者更高优先级的线程。
线程加入
join()方法,等待其他线程终止。在当前线程中调用另一个线程的join()方法,则当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。
线程唤醒
Object类中的notify()方法,唤醒在此对象监视器上等待的单个线程。如果所有线程都在此对象上等待,则会选择唤醒其中一个线程。选择是任意性的,并在对实现做出决定时发生。线程通过调用其中一个 wait 方法,在对象的监视器上等待。 直到当前的线程放弃此对象上的锁定,才能继续执行被唤醒的线程。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争;例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。类似的方法还有一个notifyAll(),唤醒在此对象监视器上等待的所有线程。
线程同步
public class MultiThread {
public static void main(String[] args) {
Ticket ticket = new Ticket();
Thread t1 = new Thread(ticket);
Thread t2 = new Thread(ticket);
Thread t3 = new Thread(ticket);
t1.setName("张三");
t2.setName("李四");
t3.setName("王五");
t1.start();
t2.start();
t3.start();
}
}
class Ticket implements Runnable{
private int num =100;
@Override
public void run() {
while (true) {
synchronized (this) {
if(num>0){
Thread currend = Thread.currentThread();
System.out.println(currend.getName()+"抢到第"+num+"张票");
num--;
}
else{
break;
}
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MultiThread1 {
public static void main(String[] args) {
Ticket1 ticket1 = new Ticket1();
Thread t1 = new Thread(ticket1);
Thread t2 = new Thread(ticket1);
Thread t3 = new Thread(ticket1);
t1.setName("张三");
t2.setName("李四");
t3.setName("王五");
t1.start();
t2.start();
t3.start();
}
}
class Ticket1 implements Runnable{
private int num =100;
private Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
lock.lock();
if(num>0){
Thread currend = Thread.currentThread();
System.out.println(currend.getName()+"抢到第"+num+"张票");
num--;
}
else{
break;
}
} finally {
lock.unlock();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}