多线程基本介绍

什么是多线程

线程和进程一样,线程是比进程更小的单位,所谓多线程就是进程里面执行更多更小的程序单元,这个程序单元就叫做线程,进程里的线程可以存在多个,同时进行

怎么创建线程

两种,一种是继承Thread类,一种是实现Runnable接口

继承和实现的区别

java程序的特点是单继承多实现,用继承有局限性,开发建议用实现的方法创建线程

为什么要重写run方法

该类用于存储线程要运行的代码,该存储功能就是run方法,类似于java程序里面的主线程main方法
d.start()和d.run()的区别
前者是开启线程并执行线程的run方法,后者仅仅是调用方法,而线程创建了并没有运行

线程的状态

被创建
运行(start())
临时状态(阻塞)-具备运行资格但没有执行权
冻结-(sleep(time))(wait())放弃执行资格(sleep时间到或notify返回运行状态)
消亡(stop)

多线程的安全问题

当多条语句再操作一个共享数据时,一个线程只执行了一部分,还没有执行完,另一个线程就参与进来,导致共享数据错误
解决办法:同步代码块/同步函数
同步代码块

class MyThread3 extends Thread{
    int tick=100;
    Object obj=new Object();
    public   void  run(){
        while(true){
            synchronized (obj) {
                if(tick>0){
                    try {
                        Thread.sleep(10);
                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                    System.out.println(Thread.currentThread().getName()+"..."+tick--);
                }
            }
        }
    }
}

同步函数:注意要把需要同步的函数提取出来再synchronized ,不然会把其他线程挡住,打印的结果只有一个线程在执行

class MyThread extends Thread{
    int tick=100;
    public void run(){
        while(true){
            show();
        }
    }
    public synchronized void show(){
        if(tick>0){
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                // TODO: handle exception
            }
            System.out.println(Thread.currentThread().getName()+"..."+tick--);
        }
    }
}

死锁

同步也会导致死锁的出现
原因是同步会占用一个锁,当另一个线程也需要这个锁的时候就会导致死锁的情况

public class test{

    public test() {
        // TODO Auto-generated constructor stub
    }
    public static void main(String[] args) {
    Object o1 = new Object();
        Object o2 = new Object();
        Thread t1 = new Thread(new T1(o1, o2));
        Thread t2 = new Thread(new T2(o1, o2));
        t1.start();
        t2.start();
    }
}
class T1 implements Runnable {
    Object o1;
    Object o2;
    T1(Object o1, Object o2) {
        this.o1 = o1;
        this.o2 = o2;
    }
    @Override
    public void run() {
        int tick=100;
        synchronized (o1) {
                if(tick>0){
                    try {
                        Thread.sleep(10);
                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                    System.out.println(Thread.currentThread().getName()+"..."+tick--);
                }
            synchronized (o2) {
            }
        }
    }
}
class T2 implements Runnable {
    Object o1;
    Object o2;
    T2(Object o1, Object o2) {
        this.o1 = o1;
        this.o2 = o2;
    }
    @Override
    public void run() {
        int tick=100;
        synchronized (o2) {
                if(tick>0){
                    try {
                        Thread.sleep(10);
                    } catch (Exception e) {
                        // TODO: handle exception
                    }
                    System.out.println(Thread.currentThread().getName()+"..."+tick--);
                }
            synchronized (o1) {
            }
        }
    }
}

打印结果是
Thread-1…100
Thread-0…100

等待唤醒机制

wait()把线程放进线程池
notify()/notifyAll()线程池唤醒线程
都使用在同步中,因为要对持有锁的线程操作等待和唤醒必须是同一个锁
为什么等待唤醒定义在object中?
因为锁可以是任意对象,所以可以被任意对象调用的方法定义在object中

停止线程

1.stop()方法–已过时
2.停止线程,就是让run方法结束,开启多线程运行,运行代码通常是循环结构,只要控制住循环结构,就可以让run方法结束
3.interrput-当没有指定的方式让冻结的线程恢复到运行状态,这时需要对冻结状态进行清除,强制让线程恢复到运行状态中来,这样就可以操作标记让线程结束

守护线程

setDaemon()
又叫后台运行线程,当所有前台线程结束后,后台线程自动结束
定义在线程启动之前

join

t1.join()
当前线程调用另一个线程的join方法,当前线程会进入阻塞状态,直到join方法执行完毕
join可以用来临时加入线程执行

优先级

就是抢资源的频率
一共10级,默认5
一般有三级,最高-10,最低-1,默认-5,可以通过setPriority设置

t1.setPriority(Thread.MAX_PRIORITY);

yield

暂停当前正在执行线程对象,执行其他的线程

猜你喜欢

转载自blog.csdn.net/qq_29485643/article/details/81514058