美文网首页
一、多线程基础

一、多线程基础

作者: 小绵羊你毛不多 | 来源:发表于2018-08-21 13:24 被阅读0次

多线程基础

基本概念

同步、异步

  • 同步 线程B要等待线程A的执行结果之后才能执行。要顺序执行
image
  • 异步 相对同步来说,彼此独立,在在等待某事件的过程中可以继续做自己的事。
image

这个更直观 小人相当于一个线程

image

并行/并发

并发和并行是异步的两种实现形式,并行是真正的异步

  • 并发

    • 单核cpu情况,同一时刻只能分配给一个线程使用。其他等待。是逻辑层面的同时工作
    image
  • 并行

    • 多核cpu情况下,每个cpu都可以分配一个线程使用,同一时刻执行多个并发任务。叫并行


      image

线程状态

image

线程状态共5种:创建、就绪、运行、==阻塞(阻塞、等待、锁定)==、终止。

创建线程

  • 继承Thread类

public class A extends Thread {
    //继承Thread类 实现run接口
    @Override
    public void run() {
        System.out.println("123");
    }

    public static void main(String[] args) {
        A a = new A();//创建线程,线程进入创建状态
        a.start();//开启线程,线程进入runnable
    }
}

  • 实现Runable接口
public class A implements Runnable {
    //继承Thread类 实现run接口
    @Override
    public void run() {
        System.out.println("123");
    }

    public static void main(String[] args) {
        //创建一个runable实现类的对象
        A a = new A();
        //不是启动线程,只是方法调用
       a.run();
    }
}
  • 实现Callable接口
public class A implements Callable<Integer> {
    //继承Callable类 实现call接口 call具有返回值
    @Override
    public Integer call() throws Exception {
        return 123;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建一个callable实现类的对象
        A a = new A();
        //用FutureTask封装
        FutureTask<Integer> future = new FutureTask<Integer>(a);
        //创建一个线程
        Thread thread = new Thread(future);
        thread.start();
        //线程启动后可以获取返回值
        Integer integer = future.get();
        System.out.println(integer);
    }
}

实现Runnable接口比继承Thread类优势:

  • 线程池只能放入实现Runable的

  • 避免单继承的限制

  • 代码被多个线程共享,代码和数据独立,例如

    • 继承Thread
int ticket=10;

MyThread t1=new MyThread();
t1.start();
MyThread t2=new MyThread();
t2.start();
//上面的代码  就会卖出20张票 没有数据共享
    • 实现接口
int ticket=10;

MyThread t=new MyThread();
t.run();
t.run(); 
//这样多个线程的时候,就能实现数据共享

线程其他状态

  • Runnable(就绪)

    线程调用start()方法,状态为可执行,等待获取cpu的使用权

  • Running(运行状态)

    获得cpu的使用权,执行代码。

  • Blocked(阻塞)

    • 等待阻塞

      执行wait()方法,jvm把该线程放入==等待池==

    • 同步阻塞

      获取同步锁时,锁被其他线程占用,jvm把该线程放入==锁池==

    • 其他阻塞

      执行sleep()或join()或发出i/o请求时,jvm把线程设置为阻塞状态

常用函数说明

  1. sleep()

    • 在指定的毫秒数内让线程休眠,进入阻塞状态。
  2. join()

    • 主线程需要等待调用join的子线程执行完毕。
  3. yield() 退让

    • 暂停当前正在执行的线程对象,并执行其他线程,该线程进入runnable状态
    • 目的:是为了让相同优先级的线程之间轮转执行。
    • 实际情况下,并不一定有效果,因为让步之后,该线程还是有可能被再次选中
sleep yield
在指定时间内肯定不会被执行 随时都可以获取锁
允许较低优先级的线程获得运行机会 只能同级
  1. interrupt() 中断
    • 并不能中断线程!
    • 只是给线程发出一个中断信号。
  2. wait()休眠
    • 线程在获取对象锁之后,释放对象锁,所以必须是再synchronized{}中
  3. notify() 唤醒
    • 线程对对象锁的唤醒操作。也要和synchronized{}搭配使用
    • notify并不能马上获取对象锁,而是再synchronized语句块结束,自动释放锁之后,jvm在所有的wait()的线程中随机选取。
  • 有个经典的题,就是三个线程。分别打印10次A、B、C,要求顺序执行

多种实现

思路如图 image
public class MyThreadPrinter implements Runnable {
    private String name;
    private Object prev;
    private Object self;

    /**
     *
     * @param name   需要打印的东西
     * @param prev   上一个对象
     * @param self   自己
     */
    private MyThreadPrinter(String name, Object prev, Object self) {
        this.name = name;
        this.prev = prev;
        this.self = self;
    }

    @Override
    public void run() {
        int count = 10;
        while (count > 0) {
            //需要获取上一个对象的锁和本身的锁
            synchronized (prev) {
                synchronized (self) {
//重点在这
                    //打印本身的信息
                    System.out.print(name);
                    count--;
                    // 打印完 name了 可以唤醒了  因为上一个线程把本身给wait了
                    self.notify();
                }
                try {
                   // 释放锁 等待notify才可以重新获取锁
                    //比如a执行完 需要执行b 需要 b a锁 就把c给wait
                    prev.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    public static void main(String[] args) throws Exception {
        Object a = new Object();
        Object b = new Object();
        Object c = new Object();

        MyThreadPrinter pa = new MyThreadPrinter("A", c, a);
        //pa执行完 c就wait了 只有a b可以获取锁
        MyThreadPrinter pb = new MyThreadPrinter("B", a, b);
        MyThreadPrinter pc = new MyThreadPrinter("C", b, c);

        new Thread(pa).start();
        Thread.sleep(100);  //确保按顺序A、B、C执行
        new Thread(pb).start();
        Thread.sleep(100);
        new Thread(pc).start();
        Thread.sleep(100);
    }

}
  • wait / sleep
wait sleep
释放锁 没有释放锁
只能在同步快sync中使用 任何地方

相关文章

网友评论

      本文标题:一、多线程基础

      本文链接:https://www.haomeiwen.com/subject/oxodiftx.html