多线程学习总结

多线程

线程与进程

进程:是指一个内存中运行的应用程序,每个进程都有一个独立的空间
线程:1.是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程最少有一个线程
2.线程实际上是在进程基础上的进一步划分,一个进程启动之后,里面的若干执行路径又可以划分成若干个线程
分时调度:所有线程轮流使用cpu的使用权,平均分配每个线程占用cpu的时间
抢占式调度:1.优先让优先级高的线程使用cpu,如果线程的优先级相同,那么会随机选择一个(线程随机性),java使用的为抢占式调度
2.cpu使用抢占式调度模式在多个线程间进行高速的切换,对于cpu的一个核断而言,某个时刻,只能执行一个线程,而cpu的在多个线程间切换速度相对我们的感觉要快,看上去就是在同一时刻运行,其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让cpu的使用率更高

同步与异步&并发与并行

同步:排队执行,效率低但是安全
异步:同时执行,效率高但是数据不安全
并发:指两个或多个事件在同一个时间段内发生
并行:指两个或多个事件在同一时刻发生(同时发生)

继承Thread

在这里插入图片描述

每个线程都拥有自己的栈空间,公用一份堆内存
由一个线程所执行的方法,那么这个方法在这个线程里面

public class Demo1 {
    /*
        多线程技术
     */
    public static void main(String[] args) {
        //Thread
        //开启了两个线程,谁快谁慢是不确定的,谁先抢到谁先执行
        MyThread m = new MyThread();
        m.start();
        for (int i=0;i<10;i++){
            System.out.println("汗滴禾下土"+i);
        }
    }
}

public class MyThread extends Thread{


    /**
     * run方法就是线程要执行的任务方法
     */
    @Override
    public void run() {
        //这里的代码 就是一条新的执行路径
        //这个执行路径的触发方法,不是调用run方法,而是通过thread对象的start()来启动任务f
        for (int i=0;i<10;i++){
            System.out.println("锄禾日当午"+i);
        }
    }
}

实现Runnable

public class Demo2 {
    /**
     * 多线程技术
     * 实现Runnable和继承Thread相比有如下优势
     * 1.通过创建任务,然后给线程分配的方式来实现的多线程,更适合多个线程同时执行和同任务的情况
     * 2.可以避免单继承带来的局限性
     * 3.任务与线程本身是分离的,提高了程序的健壮性
     * 4.后续学习的线程池技术,接受Runnable类型的任务,不接受Thread类型的线程
     *
     * @param args
     */
    public static void main(String[] args) {
        //实现Runnable
        //1.创建一个任务对象
        MyRunnable r = new MyRunnable();
        //2.创建一个线程并为其分配一个任务
        Thread t = new Thread(r);
        //3.执行这个线程
        t.start();
        for (int i=0;i<10;i++){
            System.out.println("疑是地上霜"+i);
        }
    }
}


public class MyRunnable implements Runnable{
    @Override
    public void run() {
        // 线程的任务
        for (int i=0;i<10;i++){
            System.out.println("床前明月光"+i);
        }
    }
}

public class Demo3 {
    public static void main(String[] args) {
        //匿名内部类
        new Thread(){
            @Override
            public void run() {
                for (int i=0;i<10;i++){
                    System.out.println("hhhhhhhhh"+i);
                }
            }
        }.start();


        for (int i=0;i<10;i++){
            System.out.println("疑是地上霜"+i);
        }
    }
}

Thread类

getname 返回线程名称
getid 返回线程标识符
getpriority 返回线程优先级
setpriority 设置线程优先级
通过变量做标记的方式结束线程
sleep 暂时停止执行当前正在执行的线程,休眠
setDaemon 表示是否是守护线程或用户线程
main方法主线程,其余方法子线程
守护线程:当所有用户线程死亡之后自动死亡
用户线程:
设置和获取线程名称

public class Demo4 {
    public static void main(String[] args) {
        //如何获取线程的名称
        System.out.println(Thread.currentThread().getName());
        // 不设置名称也会有默认的名称
        new Thread(new MyRunnable(),"锄禾日当午").start();
        new Thread(new MyRunnable()).start();
        new Thread(new MyRunnable()).start();
        new Thread(new MyRunnable()).start();
    }
    static class MyRunnable implements Runnable{


        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName());
        }
    }
}

线程休眠sleep

public class Demo5 {
    public static void main(String[] args) throws InterruptedException {
        //线程呢个的休眠
        for (int i=0;i<10;i++){
            System.out.println(i);
            Thread.sleep(1000);
        }
    }
}

线程阻塞

线程阻塞(耗时操作)
所有比较消耗时间的操作,比如说常见的文件读取

线程的中断

public class Demo7 {
    public static void main(String[] args) {
        //线程的中断
        //一个线程是一个独立的执行路径,它是否应该结束,应该由其自身决定
        Thread t1 = new Thread(new MyRunnable());
        t1.start();
        for (int i=0;i<5;i++){
            System.out.println(Thread.currentThread().getName()+":"+i);
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("发现");
                return; //线程自杀
                //由外部干涉一个完整的流程死亡是不合理的
            }
        }
        // 给线程t1添加中断标记


    }
    static class MyRunnable implements Runnable{
//父接口没有申明异常抛出,那么子接口就不能申明比父更大的异常抛出
        @Override
        public void run() {
            for (int i=0;i<10;i++){
                System.out.println(Thread.currentThread().getName()+":"+i);
                try{
                    Thread.sleep(1000);
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

守护线程

线程:分为守护线程和用户线程
用户线程:当一个进程不包含任何的存活的用户线程时,进行结束
守护线程: 守护用户线程的,当最后一个用户线程结束时,所有守护线程自动死亡。

//设置为守护线程
t1.setDaemon(true);

线程安全问题

public class Demo9 {
    public static void main(String[] args) {
        //线程不安全
        Runnable run = new Ticket();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();


    }
    static class Ticket implements Runnable{
        //总票数
        private int count = 10;
        @Override
        public void run() {
            while(count>0){
                //卖票
                System.out.println("正在准备卖票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println("出票成功。余票"+count);


            }
        }
    }


}

线程安全1-同步代码块

线程不安全的原因:多个线程同时执行,去争抢一个数据,去同时操作一个数据,那么导致某个数据在判断和自己使用时不一样,导致运行不符合预期。

public class Demo10 {
    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        //线程不安全
        //解决方法1:同步代码块
        //任何对象都可以打标记作为锁对象
        //格式:synchronized(锁对象){
        //
        // }
        Runnable run = new Ticket();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();


    }
    static class Ticket implements Runnable{
        //总票数
        private int count = 10;
        private  Object o = new Object();
        @Override
        public void run() {
            //不能每个线程开自己的锁,要开同一把锁
//            Object o = new Object();
                while (true) {
                    synchronized (o) {
                        if (count > 0) {
                            //卖票
                            System.out.println("正在准备卖票");
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            count--;
                            System.out.println(Thread.currentThread().getName()+"出票成功。余票" + count);
                        }else{
                            break;
                        }
                    }
                }
        }
    }


}

线程安全2-同步方法

public class Demo11 {
    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        //线程不安全
        //解决方法:同步方法
        Runnable run = new Ticket();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();


    }
    static class Ticket implements Runnable{
        //总票数
        private int count = 10;
        private  Object o = new Object();
        @Override
        public void run() {
            while (true) {
                boolean flag = sale();
                if (!flag){
                    break;
                }
            }
        }
        public synchronized boolean sale(){
            //在方法内部,谁调用锁对象就是谁==this
            //如果该方法是静态的话就是class,比如ticket.class
            
            if (count > 0) {
                //卖票
                System.out.println("正在准备卖票");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println(Thread.currentThread().getName()+"出票成功。余票" + count);
                return true;
            }
            return false;
        }


    }
}

线程安全2-显式锁Lock

同步代码块和同步方法都属于隐式锁

显式锁和隐式锁的区别

public class Demo12 {
    /**
     * @param args
     */
    public static void main(String[] args) {
        //线程不安全
        //解决方法3:显式锁  Lock 子类 ReentrantLock
        Runnable run = new Ticket();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();


    }


    static class Ticket implements Runnable {
        //总票数
        private int count = 10;
        //显式锁l
        private Lock l = new ReentrantLock();
        private Object o = new Object();


        @Override
        public void run() {
            while (true) {
                l.lock();
                if (count > 0) {
                    //卖票
                    System.out.println("正在准备卖票");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count--;
                    System.out.println(Thread.currentThread().getName() + "出票成功。余票" + count);
                } else {
                    break;
                }
                l.unlock();
            }
        }
    }
}

公平锁和非公平锁

公平锁能保证:老的线程排队使用锁,新线程仍然排队使用锁
非公平锁保证:老的线程排队使用锁;但是无法保证新线程抢占已经在排队的线程的锁。

//显式锁 l: fair参数为true就表示是公平锁

线程死锁

public class Demo13 {
    public static void main(String[] args) {
        //线程死锁
        Culprit c = new Culprit();
        Police p = new Police();
        new MyThread(c,p).start();
        c.say(p);
    }
    static class MyThread extends Thread{
        private Culprit c;
        private Police p;
        public MyThread(Culprit c,Police p){
            this.c = c;
            this.p = p;
        }


        @Override
        public void run() {
            p.say(c);
        }
    }
    //罪犯
    static class Culprit{
        public synchronized void say(Police p){
            System.out.println("罪犯:你放了我,我放人质");
            p.fun();
        }
        public synchronized void fun(){
            System.out.println("罪犯被释放了,罪犯也放了人质");
        }
    }
    //警察
    static class Police{
        public synchronized void say(Culprit c){
            System.out.println("警察:你放了人质,我放过你");
            c.fun();
        }


        public synchronized void fun(){
            System.out.println("警察救了人质,但是罪犯跑了");
        }




    }
}

多线程通信问题

wait:导致当前线程等待他被唤醒,通常是通知或中断
notify:唤醒正在此对象监控器上等待的单个线程
notifyAll:唤醒等待此对象监视器的所有线程

public class Demo14 {
    /**
     * 多线程通信问题,生产者和消费者问题
     * @param args
     */
    /**
     * 多线程通信问题, 生产者与消费者问题
     * @param args
     */
    public static void main(String[] args) {
        Food f = new Food();
        new Cook(f).start();
        new Waiter(f).start();
    }


    //厨师
    static class Cook extends Thread{
        private Food f;
        public Cook(Food f) {
            this.f = f;
        }


        @Override
        public void run() {
            for(int i=0;i<100;i++){
                if(i%2==0){
                    f.setNameAndSaste("老干妈小米粥","香辣味");
                }else{
                    f.setNameAndSaste("煎饼果子","甜辣味");
                }
            }
        }
    }
    //服务生
    static class Waiter extends Thread{
        private Food f;
        public Waiter(Food f) {
            this.f = f;
        }
        @Override
        public void run() {
            for(int i=0;i<100;i++){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                f.get();
            }
        }
    }
    //食物
    static class Food{
        private String name;
        private String taste;


        //true 表示可以生产
        private boolean flag = true;


        public synchronized void setNameAndSaste(String name,String taste){
            if(flag) {
                this.name = name;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                this.taste = taste;
                flag = false;
                this.notifyAll();
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        public synchronized void get(){
            if(!flag) {
                System.out.println("服务员端走的菜的名称是:" + name + ",味道:" + taste);
                flag = true;
                this.notifyAll();
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

线程的六种状态

在这里插入图片描述
在这里插入图片描述

带返回值的线程Callable

之前的进程,和主进程一起走
callable既可以实现一起走,也可以等callable完成给出结果主进程再进行
get 如果需要,最多等待计算完成的给定时间,然后检索其结果(如果可用)

public class Demo15{
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable c = new MyCallable();
FutureTask task = new FutureTask<>©;
// task.isDone();//判断子线程是否执行完毕
// task.cancel();//取消执行
new Thread(task).start();
Integer j = task.get();
System.out.println(“返回值”+j);
for (int i=0;i<10;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}

static class MyCallable implements Callable<Integer>{


    @Override
    public Integer call() throws Exception {

// Thread.sleep(3000);

        for (int i=0;i<10;i++){
            try {
                Thread.sleep(100);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(i);
        }
        return 100;
    }
}

}
线程池概述
缓存线程池

public class Demo16 {
    //线程池


    /**
     * 缓存线程池
     * 长度无限制
     * 任务加入后的执行流程
     * 1.判断线程池是否存在空闲线程
     * 2.存在则使用
     * 3.不存在,则创建线程,并放入线程池,然后使用
     * @param args
     */
    public static void main(String[] args) {
        //创建线程
        //创建任务
        //执行任务
        //关闭线程
        ExecutorService service = Executors.newCachedThreadPool();
        //指挥线程池中执行新的任务
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });
    }
}

定长线程池

public class Demo17 {
    /**
     * 定长线程池
     * (长度是指定的数值)
     * 任务加入后的执行流程
     * 1.判断线程池是否存在空闲线程
     * 2.存在则使用
     * 3.不存在空闲线程,且线程池未满的情况下,则创建线程,并放入线程池,然后使用
     * 4.不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
     * @param args
     */
    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(2);
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }


            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });
    }
}

单线程线程池

public class Demo18 {
    /**
     * 单线程线程池
     * 执行流程:
     * 1.判断线程池 的哪个线程 是否空闲
     * 2.空闲则使用
     * 3.不空闲则等待池中的单个线程空闲后使用
     * @param args
     */
    public static void main(String[] args) {
        ExecutorService service = Executors.newSingleThreadExecutor();
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"锄禾日当午");
            }
        });


    }
}

周期任务定长线程池

public class Demo19 {
    /**
     * 周期任务 定长线程池时机触发时,自动执行某任务
     * 周期任务执行时
     * 定时执行,当某个
     * @param args
     */
    public static void main(String[] args) {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(2);


        /**
         * 1.定时执行一次
         * 参数1.定时执行的任务
         * 参数2.时长数字
         * 参数3.时长数字的时间单位Time
         */
        /*service.schedule(new Runnable() {


            @Override
            public void run() {
                System.out.println("锄禾日当午");
            }
        },5, TimeUnit.SECONDS);*/
        /**
         * 周期执行任务
         * 参数1,任务
         * 参数2。延迟时长数字(第一次执行在什么时间以后)
         * 参数3.周期时长数字
         * 参数4.时长数字的单位
         */
        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("汗滴禾下土");
            }
        },5,1,TimeUnit.SECONDS);
    }
}

Lambda表达式

public class Demo21 {
    public static void main(String[] args) {
        //这个接口必须只有一个抽象方法才可以使用lambda表达式
//        print(new MyMath() {
//            @Override
//            public int sum(int x, int y) {
//                return x+y;
//            }
//        },100,200);
        //替换成lambda表达式
        print((int x, int y) -> {
                return x+y;
        },100,200);


    }
    public static void print(MyMath m,int x,int y){
        int num = m.sum(x,y);
        System.out.println(num);
    }
    static interface MyMath{
        int sum(int x,int y);
    }


}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值