多线程初级


多线程

创建线程

继承Thread创建线程

//main中
//创建Cat对象,可以当做线程使用
Cat cat = new Cat();
cat.start();//启动线程
//说明 : 当main线程启动一个子线程, 主线程不会阻塞,会继续执行
//这时 主线程和子线程是交替执行的

//1.当一个类继承了Thread类, 该类就可以当成线程使用
//2.我们会重写 run 方法, 写上自己的业务代码
//3. run Theread类 实现了 Runnable 接口的run方法
class Cat extends Thread{
    @Override 
    public void run(){//重写run方法,写上自己的业务逻辑
        while(true){
            //该线程每隔1秒,在控制台输出喵喵
            System.out.println("喵喵");
            //休眠一秒
            try{
                Thread.sleep(1000);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

实现Runnable接口创建线程

  1. java是单继承的, 在某些情况下一个类可能已经继承了某个父类, 这时在用继承Thread类方法来创建线程显然不可能了
  2. 所以通过实现Runnable接口创建线程
//main中
Dog dog = new Dog();
//不能直接调用start
//创建了Thread对象, 把dog对象(实现Runnable),放入Thread
//使用到了代理模式
Thread thread = new Thread(Dog);
thread.start();
class Dog implements Runnable{
    int count = 0;
    @Override
    public void run(){
        while(true){
            System.out.println("汪汪"+(++count));
            //休眠一秒
             try{
                Thread.sleep(1000);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

代理模式

//模拟简单代理模式
class ThreadProxy implements Runnable{//你可以把ThreadProxy类当做   真正的Thread类
    private Runnable target = null;//属性, 类型是 Runnable   
    //构造器
    public ThreadProxy(Runnable target){//传进来一个实现了Runnable接口的对象
        this.target = target;
    }
    public void start(){
        start0();//这个方法是真正实现多线程的方法
    }
    public void start0(){
        run();
    }
    
    @Override
    public void run(){
        if(target != null){
            target.run();//动态绑定
        }
    }
}

多线程机制

  1. 在多线程之中, 不是主线程结束了就意味着进程结束, 而是要等所有的线程结束.
  2. 从Java的设计来看, 通过继承Thread或者实现Runnable接口来创建线程本质没有区别
  3. 实现Runnable接口方式更加适合多线程共享一个资源的情况, 并且避免了单继承的限制

为什么是start?

如果直接调用run()方法的话, 就是一个普通的方法, 没有真正的启动一个线程, 就会把run()方法执行完毕, 才向下执行

start()方法执行过程

img

注意:

img

线程方法

通知线程退出

设置一个Boolean变量, 在线程外改变该变量. 使线程退出循环.

线程插队

  1. yield //线程的礼让. 让出cpu, 让其他线程执行, 但礼让的时间不确定, 所以也不一定礼让成功
  2. join //线程的插队. 插队的线程一旦插队成功, 则肯定会先执行完插入的线程所以的任务

用户线程和守护线程

  1. 用户线程 : 也叫工作线程, 当线程的任务执行完成或通知方式结束

  2. 守护线程 : 一般是为工作线程服务的, 当所有的用户线程结束, 守护线程自动结束, 常见的守护线程是 : GC(垃圾回收机制)

    //当我们希望当main线程结束后, 子线程自动结束, 将子线程设置为守护线程就可以
    
    *.setDaemon(true);
    

线程状态

img

Synchronized

  1. 在多线程编程, 一些敏感数据不允许被多个线程同时访问, 此时就使用同步访问技术, 保证数据在任何同一时刻, 最多有一个线程访问, 以保证数据的完整性
  2. 线程同步, 即当有一个线程在对内存进行操作时, 其他线程都不可以对这个内存地址进行操作, 直到该线程完成操作, 其他线程才能对该内存地址进行操作
//1.同步代码块
synchronized (对象){ //得到对象的锁, 才能操作同步代码
    //需要被同步代码
}
//2.同步方法
public synchronized void m (String name){  //同步方法, 在同一时刻, 只能有一个线程来执行m方法
    //需要被同步的代码
}

eg :

img

Synchronized细节

  1. 同步的局限性 : 导致程序的执行效率降低
  2. 非静态的方法中同步代码块 的锁可以是this, 也可以是其他对象(要求多个线程的锁是同一个对象)
  3. 静态的方法中同步代码块 的锁为当前类本身

释放锁

img

img


文章作者: 冬瓜冬瓜排骨汤
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 冬瓜冬瓜排骨汤 !
  目录