线程基础,线程之间的共享和协作

基础概念
CPU 核心数和线程数的关系
核心数:线程数 = 1:1 ,后面使用了超线程技术后--》1:2
CPU 时间片轮转机制
又称RR调度,会导致上下文切换
什么是进程和线程
进程:程序运行资源分配的最小单元,进程内部有多个线程会共享这个进程。
线程:CPU调度的最小单位,必须依赖进程而存在。
并发(concurrency)和并行(parallelism)
并行:同一时刻,可以同时处理事情的能力。
并发:于单位时间相关,在单位时间内可以处理事情的能力。

解释:1.并行是指两个或者多个事件在同一时刻发生,而并发是指两个或者多个事件在同一时间间隔发生。
2.并行是在不同实体上的多个事件,并发是在同一个实体上的多个事件。
3.在一台处理器上“同时”处理多个任务。在多态处理器上同时处理多个任务。如 hadoop 分布式集群。
所以并发编程的目标是充分利用处理器上的每一个核,以达到最高处理性能。
并发编程的意义,好处,和注意事项
好处:
1.充分利用cpu 的资源
2:加快用户响应的事件
3:程序模块化,异步化,可以用多线程解藕。
问题:
1:线程共享资源,存在冲突,容易导致死锁。
2:启动太多的线程,就会有搞垮机器的可能。

认识JAVA里面的线程
java 天生就是多线程的,启动一个main 就要启动最少5个线程
上代码:


/**
 * @author sxylml
 * @Date : 2019/2/25 15:35
 * @Description: java 线程,就算只启动一个main线程,JVM 也会启动其它5-6个线程
 */
public class OnlyMain {
    public static void main(String[] args) {

        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);

        for (int i = 0; i < threadInfos.length; i++) {
            System.out.println(threadInfos[i].getThreadId()+"-"+ threadInfos[i].getThreadName());
        }

    }
}

运行结果:

image.png

Attach Listener :线程是负责接收到外部的命令,而对该命令进行执行的并且吧结果返回给发送者。通常我们会用一些命令去要求jvm给我们一些反馈信息,如:java -version、jmap、jstack等等。如果该线程在jvm启动的时候没有初始化,那么,则会在用户第一次执行jvm命令时,得到启动。

signal dispather: 前面我们提到第一个Attach Listener线程的职责是接收外部jvm命令,当命令接收成功后,会交给signal dispather线程去进行分发到各个不同的模块处理命令,并且返回处理结果。signal dispather线程也是在第一次接收外部jvm命令时,进行初始化工作。

Finalizer: 用来执行所有用户Finalizer 方法的线程

Reference Handler :它主要用于处理引用对象本身(软引用、弱引用、虚引用)的垃圾回收问题。

JAVA 新启动线程的三种方式:

package com.cap1.tools;

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

/**
 * @author sxylml
 * @Date : 2019/2/25 15:42
 * @Description: 创建线程的三种方式DEMO
 */
public class NewThread {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        InteriorThread useThread = new InteriorThread();
        useThread.setName("staticInteriorThread");
        useThread.start();

        OuterUseThread outerThread = new OuterUseThread();
        outerThread.setName("OuterUseThread");
        outerThread.start();

//        继承runable 接口
        new Thread(new UseRunnable()).start();

//
        UseCallable useCallable = new UseCallable();
        FutureTask futureTask = new FutureTask(useCallable);
        new Thread(futureTask).start();
//         可以输出返回参数
        System.out.println(futureTask.get());

    }

    /**
     * 1:继承Thread 类
     *  因为非静态内部类对 main 方法而言是不直接可见的
     */
    private static class InteriorThread extends Thread {
        @Override
        public void run() {
            System.out.println("线程信息 ID:[ "+Thread.currentThread().getId()+"] name: ["+Thread.currentThread().getName()+ "] I'm  extends Thread");
        }
    }

    /**
     * 2:实现Runnable 接口
     */
    private static class UseRunnable implements Runnable {

        @Override
        public void run() {
            System.out.println("线程信息 ID:[ "+Thread.currentThread().getId()+"] name: ["+Thread.currentThread().getName()+ "] I'm  implements Runnable");
        }
    }

    /**
     *  3 实现 Callable 接口是允许有返回类型的,类型就是接口《泛型》
     */
    private static class UseCallable implements Callable {

        @Override
        public String call() throws Exception {
            System.out.println("线程信息 ID:[ "+Thread.currentThread().getId()+"] name: ["+Thread.currentThread().getName()+ "] I'm  implements Callable");
            return "CallableResult";
        }
    }


}



class OuterUseThread extends Thread {
    @Override
    public void run() {
        System.out.println("线程信息 ID:[ "+Thread.currentThread().getId()+"] name: ["+Thread.currentThread().getName()+ "] I'm  extends Thread");
    }
}

运行结果:


image.png

JAVA线程的生命周期:

image.png

新建状态(New):当线程对象对创建后,即进入了新建状态,如: InteriorThread t = new InteriorThread();
就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就 绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

线程的 run,start 方法

/**
 * @author sxylml
 * @Date : 2019/2/25 16:27
 * @Description:
 */
public class StartAndRun {
    private static class RunThread extends Thread {
        @Override
        public void run() {
            int i = 5;
            while (i > 0) {
                // 休眠一千毫秒
                SleepTools.ms(100);
                System.out.println("i'm " + Thread.currentThread().getName() + " i=" + i--);
            }
        }
    }
    public static void main(String[] args) {
        Thread beCalled = new RunThread();
        beCalled.setName("beCalled");
        beCalled.run();  // 面向对象,这样直接调用run 和普通类一样 : run 归谁调用,就归那个线程,這样运行结果就是main
        beCalled.start();// 只有调用start() ,才会是线程
    }
}

image.png

守护线程:

public class DaemonThread {

    private static class UseThread extends Thread {

        @Override
        public void run() {

            String threadName = Thread.currentThread().getName();
            try {
                while (!isInterrupted()) {
                    System.out.println(threadName + " extend Thread");
                    // 抛出异常
                    Thread.sleep(100);
                }
                // 抛出异常這代码就不执行咯
                System.out.println(threadName + " interrupted " + isInterrupted());
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println(threadName + " try  interrupted " + isInterrupted());
                Thread.currentThread().interrupt();
            } finally {
                // 是守护线程的的情况,不一定执行
                System.out.println("-------------finally -----------------");
            }

        }
    }

    public static void main(String[] args) throws InterruptedException {

        UseThread useThread = new UseThread();
        // 守护线程 和主线程共死,finally不能保证一定执行
        useThread.setDaemon(true);
        useThread.start();
        Thread.sleep(1000);
        // 发送中断通知
        useThread.interrupt();
    }
}

如何正确的终止线程

1:线程自然终止:自然执行完毕或抛出未处理异常
stop(),resume(),supende() 已经不建议使用,stop()会导致线程不会正确释放资源,suspend()容易导致死锁。

2:调用interrupt() 方法中断一个线程,并不是强行关闭這个线程,只是跟這个线程打个招呼,讲线程的中断标志设置为true,线程是否中断,由线程本身决定。
isInterrupted() 判断当前线程是否处于中断状态。
static 方法interrupted() 判定当前线程是否处于中断状态,同时中断标志位改为false.
方法如果抛出interruptedException ,线程的中断标志位会被复位或成false ,如果确实是需要中断线程,要求我们自己在catch 语句块里再次调用interrupt().


/**
 * @author sxylml
 * @Date : 2019/2/25 15:52
 * @Description: 如何正确的中断线程
 */
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 in while !  in interrupt flag is " + this.isInterrupted());
            }
//               当发送了中断请求,并且中断标识改变了,则退出循环
            System.out.println(threadName + " is run out while !  in interrupt flag is " + this.isInterrupted());
        }
    }


    public static void main(String[] args) {
        Thread endThread = new UseThread("endThread");
        endThread.start();
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("向线程发送中断请求!");
        endThread.interrupt();
    }


}

image.png
public class EndRunnable {

    private static class UseRunable implements Runnable {

        @Override
        public void run() {

            String threadName = Thread.currentThread().getName();
            while (!Thread.currentThread().isInterrupted()) {
//                当没有向线程发送中断请求,这执行循环里面的值
                System.out.println(threadName + " is running in while !   interrupt flag is " + Thread.currentThread().isInterrupted());
            }

//            当发送了中断请求,并且中断标识改变了,则退出循环
            System.out.println(threadName + " is run out while !   interrupt flag is " + Thread.currentThread().isInterrupted());
            
        }
    }


    public static void main(String[] args) throws InterruptedException {

        UseRunable useRunable = new UseRunable();
        Thread thread = new Thread(useRunable, "endRunnable");
        thread.start();
        Thread.sleep(20);
        System.out.println("发起中断请求!");
        thread.interrupt(); // 发起中断信号
    }
}

image.png

你可能感兴趣的:(线程基础,线程之间的共享和协作)