线程之前笔记

  1. 线程是操作系统能够进行运算调度的最小单位,是进程中的实际运作单位

  2. 线程和进程的区别

    1.每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销
    2.线程可以当成轻量级的进程,每个线程有独立的工作内存,切换开销小
    3.多进程:在操作系统中同时运行多个程序
    4.多线程:在同一程序中有多个顺序流(功能)同时执行(多核cpu)
    5.单线程:同一时间点只能有一个进程在执行(采用时间片轮转,让多个线程轮流执行。因为cpu执行速度快--假多线程)
  3. 线程理解

    每个分支都叫一个线程,main叫主分支(主线程)
    机器上的一个.class文件,机器上的一个.exe文件,这个叫做一个进程。程序的执行过程都是这样的:首先把程序的代码放到内存的代码区里面
    代码放到代码区后并没有马上开始执行,但这时候说明了一个进程准备开始,进程已经产生了,但还没有开始执行,这就是进程,所以进程其实是一个静态的概念,它本身就不能动
    平常所说的进程的执行指的是进程里面主线程开始执行了,也就是main()方法开始执行了。进程是一个静态的概念,在我们机器里面实际上运行的都是线程

    程序的执行流程:
    1.操作系统将分块的程序运输到内存对应的区间,过程中建立一个对应的表方便寻址
    2.当程序跑起来后根据局部性规律(当调用一块代码后,周围的代码也会被调用),一点点的调入内存中
    3.寻址过程中使用虚拟地址分配,就可以运行那些占较大内存的程序

  4. java中的线程

    java.lang.Thread 类的实例就是一个线程但是它需要调用java.lang.Runnable接口来执行,
    由于线程类本身就是调用的Runnable接口
    所以你可以继承java.lang.Thread 类或者直接调用Runnable接口(推荐)来重写run()方法实现线程
  5. 线程的创建和启动

    • 继承Thread并重写run方法
      class MyThread extends Thread {
      public void run(){
      //线程体
      }
      }
    • 实现Runnable接口
      //定义一个线程类
      public class ThreadTest implements Runnable{
      public void run() {
      // TODO Auto-generated method stub
              线程体
      }
      }
      public class TestThread1{
      public static void main(String args[]){
      ThreadTest tt = new ThreadTest();
      tt.run();//就会执行run()方法再执行main方法
      Thread t = new Thread(tt);//启动一个新的线程需要Thread对象
      t.start();//启动新线程与主线程一起执行(交替执行)
      for(int i=0;i<10;i++){
          System.out.println("maintheod:"+i);
      }
      }
      }
      public static Thread currentThread()//获取当前线程的引用
  6. start与run

    start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,
    当调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程
  7. 线程状态转移

    阻塞状态(等待状态)

  • 创建一个新线程start准备好后进入就绪态(标上优先级别),进入cpu执行(线程调度器决定哪个线程进入运行态)

  • 时间片用完线程执行完后线程终止/遇到死锁后kill掉/时间片用完没有执行完的线程进入等待态
  1. 线程使用

    sleep(毫秒):休眠当前线程,进入等待状态,当休眠时间到解除等待状态,进入就绪状态等待cpu运行(睡眠时不会释放锁)
    yield()让出cpu给其他线程
    join()合并当前线程,让线程按照当前代码写的顺序执行
    wait():与synchronized关键字一起使用,进程进入等待状态,当notify/notifyall调用后解除等待态,wait调用后会释放锁,所以拿到锁后才可以运行
    setPriority()设置线程优先级别
  2. 线程同步

    对象互斥锁(synchronized)--保证共享数据操作的完整,这时就只有一个线程可以访问该对象/方法

    synchronized(this) {
    共享(同步)数据块
    }
    synchronized public void xx(){
    共享(同步)方法
    }
  3. 线程同步出现的问题

    死锁:

    1.在同步数据块内调用了其他同步代码-----减少同步锁定
    2.指定获取锁的顺序:比如规定,只有获得A锁的线程才有资格获取B锁
  4. synchronized

    1.synchronized进行加锁操作,synchronized的锁机制会根据线程竞争情况在运行时会有偏向锁(单一线程)、轻量锁(多个线程访问synchronized区域)、对象锁(重量锁,多个线程存在竞争的情况)、自旋锁等。该关键字是一个几种锁的封装。
    2.进入时,执行monitorenter(显式同步)将计数器+1,释放锁时计数器-1
    3.当一个线程判断到计数器为0时,则当前锁空闲,可以占用;反之,当前线程进入等待状态
  5. volatile

    1.volatile关键字是与Java的内存模型有关(主内存和工作内存)
    2.volatile可以直接与主内存产生交互,进行读写操作,保证可见性
    2.volatile能确保可见性:可见性是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。
    3.volatile禁止进行指令重排序。
    4.volatile变量可以保证下一个读取操作会在前一个写操作之后发生
  6. 线程池

    java.util.concurrent.ThreadPoolExecutor类就是一个线程池。

当前线程池大小:表示线程池中实际工作者线程的数量
最大线程池大小(maxinumPoolSize):表示线程池中允许存在的工作者线程的数量上限
核心线程大小(corePoolSize ):表示一个不大于最大线程池大小的工作者线程数量上限

线程code

  • 按顺序打印0~9--使用wait让未达到条件的线程进入等待态
    public class ThreadTest {
    private static final int endNum = 10;
    public static void main(String[] args) {
    //按需求新建多个线程,让每个线程实现对应的功能
        TTest[] test = new TTest[10];
        for(int i=endNum-1;i>=0;i--) {
            test[i] = new TTest(i);
            test[i].start();
        }
    }
    }
    public class TTest extends Thread {
    private static final int endNum = 10;
    static int orderNum = 0;
    //对象锁,只有获取该锁才能继续操作
    static Object object = new Object();
    private int printNum;
    public TTest(int printNum) {
        this.printNum = printNum;
    }
    @Override
    public void run() {
        synchronized (object) {
    //用户判断程序是否执行完毕
            while(orderNum < endNum) {
                if(orderNum == printNum) {
                    System.out.println(printNum);
                    orderNum ++;
                    if(orderNum ==10) {
                        System.out.println("打印完成");
                    }
                    object.notifyAll();
                }else {
                    try {
    //每个线程都对应一个参数,根据参数判断是否应该输出,如果不符合,当前线程就进入等待态,唤醒后再执行
                        object.wait();
                    } catch (Exception e) {
                        System.out.println("线程:"+printNum+"被打断了");
                        e.printStackTrace();
                    }
                } 
            }
        }
    }
    }

ref:
java基础学习总结——线程(一)
你真的了解volatile关键字吗?
Java并发编程:volatile关键字解析