Java并发编程基础(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014732537/article/details/78680802

前言

本篇博客主要从三个方面记述。第一,对线程进行简要的介绍,理解什么是线程,为什么使用多线程。第二,介绍线程拥有的状态,以及线程各个状态之间的转换,并举相关的例子进行说明。第三,介绍线程的操作,对线程的创建、终止、中断、挂起和继续执行等进行举例说明。

线程的介绍

讲到线程,首先会提到的是进程,具体什么是线程,什么是进程尼?

概念上看,进程是具有一定独立功能的程序,它是关于某个数据集合的一次运行活动,进程是系>统进行资源分配和调度的一个独立单位。线程是进程的一个实体,是CPU调度和分派的基本单位。>线程是轻量级的进程,是程序执行的最小单元。

我们知道程序的并发设计,带来了生产的高效性。当然前提是正确的使用好程序的并发性。那么为什么需要引入线程尼?

一方面,在进程内创建、终止线程比创建、终止进程要快;
另一方面,同一进程内的线程间切换比进程间的切换要快,尤其是用户级线程间的切换。

线程的状态

Java线程的生命周期中可能会处于6个状态,JDK中的State枚举出了以下六个状态。

public enum State {
  NEW,//初始状态,线程被构建,但还没被调用start方法
  RUNNABLE,//运行状态,Java线程中将操作系统中的就绪和运行两种状态统称为“运行中”
  BLOCKED,//阻塞状态,表示该线程阻塞于锁
  WAITING,//等待状态,表示该线程需要等待其他线程做出一些特定的通知
  TIMED_WAITING,//超时等待状态,可以设置阻塞等待的时间,超过时间自动返回。
  TERMINATED;//终止状态,表示该线程运行完毕
}

Java线程状态图
其中RUNABLE状态和操作线程叙述的运行状态是有区别的,RUNABLE状态笼统的将“就绪和运行”归为运行中状态
状态图说明:

1.NEW,刚创建的线程,还没开始执行,也就是说线程中的代码还没开始运行。
2.RUNNABLE,运行中状态。
2.1当线程对象调用start方法,线程进入就绪状态,此时还是没有开始执行线程代码,只是该线程进入可运行线程池,等待被调度线程选中,获取CPU运行时间片。
2.2如果该线程进入就绪状态后,获取到CPU运行时间片,进入运行状态,调度该线程并运行run方法里面的代码,即线程中的代码开始执行。
3.BLOCKED,阻塞状态,线程执行过程中遇到了synchonrized同步块,将会进入阻塞状态,此时,该线程便会停止运行,直到获取到该同步块的锁。此时的并发级别是阻塞。
4.WAITING和TIMED_WAITING,等待和超时等待状态,两个状态都表示等待,但是区别在于WAITING是无时间限制的等待,而TIMED_WAITING是有时间限制的等待。一旦进入到等待状态,该线程的代码也就会停止继续运行,直到其他线程进行通知唤醒,该线程才会回到运行状态。TIMED_WAITING在等待到超过一定的时间后也会返回到运行状态。通常搭配使用的是wait()和notify()方法。
5.TERMINATED,结束状态,即线程执行完毕,或者线程运行完run方法后将会进入到终止状态,当然也可能发生其他因异常而进入终止状态的情况。

线程的操作

线程的创建

Java多线程开发中提供了3中创建线程的方式。
方式一 继承Thread类实现线程类

//1.继承Thread
public class Demo1Thread extends Thread{
//2.复写run方法,线程执行的代码体    
    @Override
    public void run() {
       //something to do
       ......
    }
}
//3.启动线程,进入就绪状态
new Demo1Thread().start()

方式二 实现Runnable接口实现线程类

//1.实现Runnable接口
public class Demo2Thread implements Runnable{
//2.复写run方法,线程执行的代码体    
    @Override
    public void run() {
       //something to do
       ......
    }
 }
 //启动线程
 new Thread(new Demo2Thread()).start()

方式三 通过Callable和Future来创建线程

//1.实现Callable接口,并实现call()方法,该call()方法将作为线程执行体,并且有返回值。
class  Demo3Thread implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
         //something to do
         ......
         //返回线程的运行结果
        return new Integer(9);
    }
}
//2.创建Callable实现类的实例,使用FutureTask类来包装Callable对象,该FutureTask对象封装了该Callable对象的call()方法的返回值。
Demo3Thread t3 = new Demo3Thread();  
FutureTask<Integer> ft = new FutureTask<>(t3); 
//3.启动线程
new Thread(ft).start();
//4.获取线程运行结果
ft.get();
线程的中断、挂起和继续执行

中断,它是线程的一个标识位属性,表示一个运行的线程是否被其他线程进行了中断操作。可以比拟为其他线程对自正在运行的该线程打了个需要中断的招呼,是否需要停止,还得看运行的线程怎么做决定。
注意:当一个线程处于中断状态时,如果再由wait、sleep以及jion三个方法引起的阻塞,那么JVM会将线程的中断标志重新设置为false

public class Demo {
    public static void main(String[] args) {
        try {
      //1 此处是当前运行的主线程main
            Demo2Thread thread1 = new Demo2Thread();
            thread.start();
            Thread.sleep(2000);
      //1.1 当前运行的主线程main向运行的thread1线程发送中断信号(打招呼)
            thread.interrupt();

        } catch (InterruptedException e) {
            System.out.println("main catch");
            e.printStackTrace();
        }
    }
}
//2.结束中断信号的线程Demo2Thread
public class Demo2Thread extends Thread {
    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 500000; i++) {
            //2.1判断是否接收到中断信号,即自身的中断标识是否被置为true
            if (this.interrupted()) {
                System.out.println("should be stopped and exit");
                break;
            }
            System.out.println("i=" + (i + 1));
        }
        //2.2尽管线程被中断,但并没有结束运行。这行代码还是会被执行
        System.out.println("this line is also executed. thread does not stopped");
    }
}
//3.获取中断信号的区别。
//3.1 interrupted函数是作用于当前线程,isInterrupted 函数是作用于调用该方法的线程对象所对应的线程。
//3.2 只有当前线程才能清除自己的中断位即interrupted函数。

线程的挂起,简单的说就是让线程进入“非可执行”状态下,在这个状态下CPU不会分给线程时间片,进入这个状态可以用来暂停一个线程的运行。在线程挂起后,可以通过重新唤醒线程来使之恢复运行。Java中通常使用suspend()和resume()和stop()来完成线程的暂停、恢复和停止。但现在已不建议使用。
不建议的原因:

suspend()挂起后,线程并不会释放已经占有的资源(锁),是属于占着资源进入睡眠状态,这容易引起需要它占有的资源其他线程处于等待或阻塞状态。
stop()方法终结一个线程后不会保证线程的资源正确的得到释放。
线程的终止

线程的终止,即线程的结束状态,不建议使用stop强行终止线程,原因如上,可以通过发送中断信号,或者设置线程的boolean值来控制线程任务是否终止。

public class Demo {
    public static void main(String[] args) {
        try {
      //1 此处是当前运行的主线程main
            Demo2Thread thread1 = new Demo2Thread();
            thread.start();
            Thread.sleep(2000);
           //1.1 当前运行的主线程main向运行的thread1线程发送中断信号(打招呼)
            thread.interrupt();
            //1.2主线程安全的停止thread线程
            //thread.setStop();

        } catch (InterruptedException e) {
            System.out.println("main catch");
            e.printStackTrace();
        }
    }
}
//2.需要终止的线程Demo2Thread
public class Demo2Thread extends Thread {
 private volatile boolean on =true;
    @Override
    public void run() {
       //2.1该线程是否终止或者饥饿到中断
        while(on&&!this.interrupted())
        {
             //do something
             ......
        }
        //2.2跳出循环
    }
    public void setstop(){
       on=false;
    }
}

没有更多推荐了,返回首页