Java线程和进程

时间:2021-11-10 19:36:06

一.线程

  1.什么是线程:

    线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。一个进程至少包含一个线程,也可以多个,线程属于进程。

  2.Java中线程经历的四个过程:

    (1)创建:

      创建一个Java线程常见的有两种方式:继承Thread类和实现Runnable接口这两种方式。

    (2)执行:

线程创建后仅仅占有了内存资源,在JVM管理的线程中还没有该线程,该线程必须调用start方法通知JVM,这样JVM就会知道又有一个新的线程排队等候了。如果当前线程轮到了CPU的使用权限的话,当前线程就会继续执行。

(3)中断:

  a.JVM将CPU的使用权限从当前线程切换到其它线程,使本线程让出CPU的使用权限而处于中断状态。

   b.线程在执行过程中调用了sleep方法,使当前线程处于休眠状态。

   c.线程在执行的过程中调用wait方法

   d.线程在使用cpu资源期间,执行了某个操作而进如阻塞状态。

 (4)死亡

  死亡的线程不在具有执行能力。线程死亡的原因有二:

     a.线程正常运行结束而引起的死亡,即run方法执行完毕。

    b.线程被提前强制终止。

  3.Thread类:

    3.1构造方法:

构造方法摘要
Thread() 
          分配新的 Thread 对象。
Thread(Runnable target) 
          分配新的 Thread 对象。
Thread(Runnable target, String name) 
          分配新的 Thread 对象。
Thread(String name) 
          分配新的 Thread 对象。
Thread(ThreadGroup group, Runnable target) 
          分配新的 Thread 对象。
Thread(ThreadGroup group, Runnable target, String name) 
          分配新的 Thread 对象,以便将 target 作为其运行对象,将指定的 name 作为其名称,并作为 group 所引用的线程组的一员。
Thread(ThreadGroup group, Runnable target, String name, long stackSize) 
          分配新的 Thread 对象,以便将 target 作为其运行对象,将指定的 name 作为其名称,作为 group 所引用的线程组的一员,并具有指定的堆栈大小
Thread(ThreadGroup group, String name) 
          分配新的 Thread 对象。

    3.2常用方法:  

方法摘要
 long getId() 
          返回该线程的标识符。
 String getName() 
          返回该线程的名称。
 int getPriority() 
          返回线程的优先级。
 void interrupt() 
          中断线程。
static boolean interrupted() 
          测试当前线程是否已经中断。
 boolean isAlive() 
          测试线程是否处于活动状态。
 boolean isDaemon() 
          测试该线程是否为守护线程。
 void join() 
          等待该线程终止。
 void join(long millis) 
          等待该线程终止的时间最长为 millis 毫秒。
 void join(long millis, int nanos) 
          等待该线程终止的时间最长为 millis 毫秒 + nanos 纳秒。
 void run() 
          如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回。
 void setName(String name) 
          改变线程名称,使之与参数 name 相同。
 void setPriority(int newPriority) 
          更改线程的优先级。
static void sleep(long millis) 
          在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
static void sleep(long millis, int nanos) 
          在指定的毫秒数加指定的纳秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。
 void start() 
          使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

    3.3相关方法使用:

      (1)继承实现Thread类:

 package com.swpu.thread;
class MyThread extends Thread{
public MyThread(String name){
super(name);
}
public void run(){
for(int i=0;i<10;i++){
System.out.println(getName()+"正在运行"+(i+1));
} }
}
public class ThreadTest { public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread mythread1=new MyThread("线程1");
MyThread mythread2=new MyThread("线程2");
mythread1.start();
mythread2.start(); } }

      (2)实现Runnable接口:

          为什么要实现Runnable接口:Java不支持多继承了不打算重写Thread类的其他方法。

 package com.swpu.thread;

 class PrintRunnable implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 1; i < 10; i++) {
System.out.println(Thread.currentThread().getName() + "正在运行"+(i++));
}
}
} public class ThreadTest { public static void main(String[] args) {
// TODO Auto-generated method stub
//如果都是使用的pr1,那就相当于资源共享
PrintRunnable pr1 = new PrintRunnable();
Thread th1 = new Thread(pr1);
PrintRunnable pr2 = new PrintRunnable();
Thread th2 = new Thread(pr2);
th1.start();
th2.start(); } }

    3.4线程的状态:

Java线程和进程

    3.5正在运行状态---->阻塞状态相关方法使用:

      (1)sleep():

        在指定的毫秒数内让正在执行的线程休眠(暂停执行),参数是休眠的时间(毫秒)。

        使用场景:定期刷新某项东西,计时间等

 package com.swpu.thread;

 class PrintRunnable implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 1; i < 10;) {
System.out.println(Thread.currentThread().getName() + "正在运行" + (i++));
//需要捕获异常(运行时退出)
try {
//休眠时间结束后,线程不会立即变成执行状态,而是变成可执行状态,需要获取CPU使用权才能变成执行状态
//因此时间需要多花一点
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} public class ThreadTest { public static void main(String[] args) {
// TODO Auto-generated method stub
// 如果都是使用的pr1,那就相当于资源共享
PrintRunnable pr1 = new PrintRunnable();
Thread th1 = new Thread(pr1);
PrintRunnable pr2 = new PrintRunnable();
Thread th2 = new Thread(pr2);
th1.start();
th2.start(); } }
     (2)join():

        等待该方法的线程结束后才能执行。也有个参数为毫秒,等待线程终止的最长时间为多少毫秒(即在该线程执行的最长时间,无论线程是否结束都会执行其他线程)。 

 package com.swpu;

 class MyThread extends Thread {
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName() + "执行第" + (i + 1));
}
} } public class ThreadTest { public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread mythread = new MyThread();
mythread.start();
try{
//抢占资源,会等待Thread-0运行完成后,其他线程才能执行
mythread.join();
}
catch(InterruptedException e){
e.printStackTrace();
}
for(int i=0;i<10;i++){
System.out.println("主线程运行第"+(i+1));
} } }

    3.6线程优先级:(优先级的设置与操作系统及工作环境都有关)

      Java线程类提供10个优先级;

      优先级可以用整个整数1-10表示,超过范围会抛出异常;

      主线程默认优先级为5。

      优先级常量:MAX_PRIORITY:线程的最高优先级10,MIN_PRIORITY:线程的最低优先级1,NORM_PRIORITY:线程的默认优先级5(主线程为5)

      优先级方法:getPriority()获得优先级,setPriority()设置优先级、

 package com.swpu;

 class MyThread extends Thread {
public void run() {
for(int i=0;i<50;i++){
System.out.println(getName()+"运行完成"+(i+1));
}
} } public class ThreadTest { public static void main(String[] args) {
// TODO Auto-generated method stub
int mainPriority=Thread.currentThread().getPriority();
System.out.println("主线程优先级为:"+mainPriority);
MyThread mythread1 = new MyThread();
MyThread mythread2 = new MyThread();
//设置两个线程的优先级
mythread1.setPriority(Thread.MAX_PRIORITY);
mythread2.setPriority(Thread.MIN_PRIORITY);
mythread1.start();
mythread2.start(); } }

  4.线程中的问题及线程同步:

    各个线程是通过竞争CPU时间而获得运行时间的;

    各CPU什么时候得到CPU时间,占用多久,是不可预测的;

    一个正在运行的线程在什么地方被暂停是不确定的。

    线程同步:synchronized关键字用在成员方法,静态方法,语句块。【防止执行过程中语句未执行完整跳到另一个线程,使取得的数据有误差】

  5.线程间通信:

    wait():在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待;
            notify(): 唤醒在此对象监视器上等待的单个线程;

    notifyAll(): 唤醒在此对象监视器上等待的所有线程。

    例:

      Queue:

 package com.swpu.queue;

 public class Queue {
private int n;
boolean flag=false;
public synchronized int get() {
if(!flag){
try{
wait();
}
catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println("获取:"+n);
flag=false;//消费完毕
//唤醒所有线程,notify()随机唤醒一个
notifyAll();
return n;
} public synchronized void set(int n) {
if(flag){
try{
wait();
}
catch(InterruptedException e){
e.printStackTrace();
}
}
System.out.println("设置:"+n);
this.n = n;
flag=true;//容器中已经有数据
notifyAll();
} }

      Producer:

 package com.swpu.queue;

 public class Producer implements Runnable{
Queue queue;
Producer(Queue queue){
this.queue=queue;
}
@Override
public void run() {
int i=0;
while(true){
queue.set(i++);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

      Consumer:

 package com.swpu.queue;

 public class Consumer implements Runnable {
Queue queue; Consumer(Queue queue) {
this.queue = queue;
} @Override
public void run() { while (true) {
queue.get();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }

      Test:

 package com.swpu.queue;

 public class Test {
public static void main(String[] args){
Queue queue=new Queue();
new Thread(new Producer(queue)).start();
new Thread(new Consumer(queue)).start();
} }

  6.Java各种线程锁:

    https://www.jianshu.com/p/fa084227c96b

二.进程

  1.什么是进程:  

    进程是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体,它有自己的生命周期。它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而被撤消。反映了一个程序在一定的数据 集上运行的全部动态过程。通过进程控制块(PCB)唯一的标识某个进程。同时进程占据着相应的资源(例如包括cpu的使用 ,轮转时间以及一些其它设备的权限)。是系统进行资源分配和调度的一个独立单位。

  2.程序:

    一段静态的代码,一组指令的有序集合,它本身没有任何运行的含义,它只是一个静态的实体,是应用软件执行的蓝本。

  3.进程和程序的区别:

进程和程序的区别
  状态 是否具有资源 是否有唯一标识 是否具有并发性
进程   动态   √   √   √
程序   静态   ×   √   ×

  4.进程的状态及转换:

    (1)就绪(Ready)状态

     当进程已分配到除CPU以外的所有必要资源后,只要在获得CPU,便可立即执行,进程这时的状态就称为就绪状态。在一个系统中处于就绪状态的进程可能有多个,通常将他们排成一个队列,称为就绪队列。

   (2)执行状态

      进程已获得CPU,其程序正在执行。在单处理机系统中,只有一个进程处于执行状态;再多处理机系统中,则有多个进程处于执行状态。

   (3)阻塞状态

     正在执行的进程由于发生某事件而暂时无法继续执行时,便放弃处理机而处于暂停状态,亦即程序的执行受到阻塞,把这种暂停状态称为阻塞状态,有时也称为等待状态或*状态。

Java线程和进程

  5.多进程相关实现:

    https://blog.csdn.net/cq340321/article/details/53364512/

三.相关参考

  程序,线程,进程详解:https://www.cnblogs.com/xiohao/p/4310644.html