Java并发编程(JUC)---线程的新建和终止

在进入Java并发编程的主要内容前,我们先从并发编程的几个基础概念说起。

1.进程和线程的区别:

进程:程序运行资源分配的最小单位,进程内有多个线程,会共享这个进程资源。
线程:CPU调度的最小单位。
引入线程的必要性: 在还没有线程这个概念之前,进程是程序资源分配的最小单位,可是进程间的变量却是独一份的,计算机在这种情况下 很难实现变量之间的共享,这样很难实现并发运行程序,使得CPU的资源大大浪费。在引入线程之后,不同的线程之间能共享同一个进程间独一份的变量,这不仅很好地实现了并发运行,也使得CPU的利用率大大提高。

2.并行与并发的区别:

并行:同一时刻,可已处理事情的能力
并发:与时间单位相关,在单位时间内处理事情的能力(不一定要同时)

举一下简单的例子:
你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。
你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。 (不一定是同时的)
你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。

饭堂里有8个窗口可以同时进行打饭,每个人打饭的时间是30s,则饭堂的并行度为8,饭堂在一分钟内的并发度为16。

3.新建线程的方式(Java里的程序天生就是多线程的)

1)类Thread:继承该类,重写run(), 新生: new Thread(类).start()
代码:

package thread基础;

/**
 * @author lenovo
 */
public class StartAndRun {
    public static class ThreadRun extends Thread{
        @Override
        public void run() {
            int i=10;
            while(i>0){
                try {
                    Thread.sleep(1000);
                    System.out.println("I am "+Thread.currentThread().getName()
                            +" and now the i="+i--);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        ThreadRun beCalled=new ThreadRun();
        beCalled.setName("BeCalled");
        beCalled.run();
    }
}

运行结果:
在这里插入图片描述

2) 接口Runnable: 实现该接口,重写run() 新生: new Thread(类).start()

3) 接口Callable:(这个接口的实现类可以有返回值,可以抛出异常)

实现该类,重写call()

新生:UseCall useCall=new UseCall(); //UseCall是我们自己书写的Callable的实现类
FutureTask<> futureTask=new FutureTask<>(useCall);
new Thread(futureTask).start();

2和3的代码示例:

package thread基础;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @author lenovo
 */
public class NewThread {

    /**
     * 实现Runnable接口
     */
    private static class UseRun implements Runnable{

        @Override
        public void run() {
            System.out.println("I am implements Runnable");
        }
    }

    /**
     * 实现Callable接口
     */
    private static class UseCall implements Callable<String> {
        @Override
        public String  call() throws Exception {
            System.out.println("I am implements Callable");
            return "CallResult";
        }
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        UseRun useRun=new UseRun();
        new Thread(useRun).start();

        UseCall useCall=new UseCall();
        //FutureTask实现了Callable到Runnable的转换
        FutureTask<String> futureTask=new FutureTask<>(useCall);
        new Thread(futureTask).start();
        System.out.println(futureTask.get());

    }
}

运行结果
在这里插入图片描述

区别: Runnable重写的run () 方法没有返回值, Callable重写的call () 方法有返回值

4.线程的终止:

1)stop() resume() suspend() ------>强制终止,不一定会释放资源 (新版的JDK中已经摒弃了这些方法,所以建议读者一般不要使用)

2)java的线程是协作的(建议使用下面方法对线程进行中断)

注:以下的方法都不是强制终止线程,它只是发出一个信号,只有我们在线程的处理逻辑对该信号进行处理,才能正真意义上的中断线程

interrupt() 中断一个线程,并不是强行关闭这个线程,只是置中断标志位为true

isInterrupted(): 判断当前线程是否处于中断状态
**-------》**由类Thread提供
static方法下的interrupted(): 判断是否处于中断状态,中断标志位改为false

代码示例:

package thread基础;

/**
 * @author lenovo
 */
public class EndThread {

    private static class UseThread extends Thread{

        public UseThread(String name){
            super(name);
        }

        @Override
        public void run() {
            String threadName=Thread.currentThread().getName();
            while (!isInterrupted()){
                System.out.println(threadName+" is run! ");
            }
            System.out.println(threadName+" interrupt flag is "+isInterrupted());
        }

        public static void main(String[] args) throws InterruptedException {
            Thread endThread=new UseThread("EndThread");
            endThread.start();
            Thread.sleep(1);
            endThread.interrupt();
        }
    }
}

运行结果
在这里插入图片描述
特别注意:当我们线程的处理逻辑中的方法会抛出InterruptedException时,线程的中断标志位会被复位为false,需要我们从自己的catch里再次中断

代码示例:

package thread基础;

/**
 * @author lenovo
 */
public class HasInterruptException {
    public static class UseThread extends Thread{
        public UseThread(String name) {
            super(name);
        }
        @Override
        public void run() {
            String threadName=Thread.currentThread().getName();
            while(!isInterrupted()){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    System.out.println(threadName+" interrupt flag is "+isInterrupted());
                    e.printStackTrace();
                    interrupt();

                }
                System.out.println(threadName);
            }
            System.out.println(threadName+" interrupt flag is "+isInterrupted());
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Thread thread=new UseThread("UseThread");
        thread.start();
        Thread.sleep(500);
        thread.interrupt();
    }
}

运行结果
在这里插入图片描述
解释:因为线程的处理逻辑中有Thread.sleep(100);它会抛出InterruptedException的异常所以它的标志位会置为false,这时我们应该在catch语句块中手动interrupt(),否则线程将不会中断

发布了19 篇原创文章 · 获赞 2 · 访问量 422

猜你喜欢

转载自blog.csdn.net/TheWindOfSon/article/details/103328246