基于Java的多线程知识初级贯通,简单易懂

线程与进程

  • 进程:每一个进程的内存空间是独立的,互不共享
  • 线程:进程中的一个执行路径,多个线程之间共享一个内存,线程之间能够自由切换,并发执行(同一时刻执行)
  • 一个进程启动之后,又可以划分为多个线程
  • 多线程是能让线程更合理的交替进行,提高cpu的使用率,而不是提高运行速度

线程的调度

  • 分时调度:把cpu时间均分,轮流使用
  • 抢占式调度:优先让优先级高的线程使用cpu,如果相同,则随机使用 ,优先级越高,抢到cpu的概率越高
  • 1000个人同时去分cpu没有1000人排队快,因为切换的时间很长

同步与异步

  • 同步:排队执行,效率低但是安全
  • 异步:同时执行,效率高但是数据不安全

并发与并行

  • 并行是指在同一时刻同时执行,并发是指在同一时间段内同时执行
  • 进程之间相互独立,可以实现并行执行,而线程之间只能是并发执行,其实就是顺执行,cpu可以按照时间切片执行,实现高速切换,

继承Thread

  • 线程停止不用stop,(有可能会无法释放资源就被关闭),通过变量做标记,再return;即可
  • sleep(参数毫秒) 线程休眠
  • setDaemon(boolean) 设置为守护线程还是用户线程
  • 守护线程:掌握不了自己,当所有用户线程死亡,他才会死亡
  • 用户线程:自己决定自己死亡

Runnable

获取和设置线程名称

线程休眠

Thread.sleep(1000);

线程阻塞

线程阻塞包括所有消耗时间的操作,比如说文件读取

线程中断

线程是否中断由其自己决定

用return; 来中断

thread.interrupt();

这个可以调用run()里面的中断异常

守护线程

thread.setDaemon(true);

这样就设置守护线程(在线程启动之前设置)

线程不安全

同步代码块synchronized

上同一把锁,使用synchronized方法

同步方法

显式锁

公平锁非公平锁

公平锁:先到先得

非公平锁:一块抢

Lock l = new ReentrantLock(true);//公平锁  默认为false(非公平)

公平死锁

线程死锁是指两个或两个以上的线程互相持有对方所需要的资源,由于synchronized的特性,一个线程持有一个资源,或者说获得一个锁,在该线程释放这个锁之前,其它线程是获取不到这个锁的,而且会一直死等下去,因此这便造成了死锁。

一个锁只能被一个线程所占用,当一个线程首先获取到这个锁之后,在该线程释放这个锁之前,其它线程均是无法获取到这个锁的。

public class Demo4 {
    /**
     * 线程死锁
     * @param args
     */
    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("警察:答应你");
        }
    }
}

解决方法:在已经有一个锁的时候避免再调用另外的锁

多线程通信问题

Object里面的wait()

Object里面的notify()唤醒随机一个 notifyAll()唤醒全部

“sleep() 和 wait() 的区别就是 调用sleep方法的线程不会释放对象锁,而调用wait() 方法会释放对象锁”

package com.java.demo;


import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class Demo4  {


    /**
     * 多线程通信问题, 生产者与消费者问题
     * @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();
                }
            }
        }
    }
}

问题解决的关键并不是添加线程安全synchronized,因为是非公平锁,关键是让厨师做饭时服务员睡着,服务员送饭时厨师睡着(厨师做完饭睡着后,服务员端菜)

线程状态Thread.start

带返回的线程Callable

之前的是一起走,这个可以一起走,也可以等待,有主次感觉

这个时候如果调用get() 则会导致系统等待callable结束

futureTask.isDone();//返回任务是否完成
futureTask.cancel();//取消任务

线程池

流程:创建线程 创建任务 执行任务 关闭线程 黑体字才是耗费时间

线程池解决了线程频繁创建导致的效率低下

定长线程池

非定长线程池会创建新的线程去执行等待的任务,而且会把一直处于空闲的线程释放掉0

后端程序本来就是多线程多缓存的

单线程:排队执行

(不)定长:并发执行

周期性的可以定时执行,而非立即执行

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class Demo61 {
    /**
     * 缓存线程池.
     * (长度无限制)
     * 执行流程:
     * 1. 判断线程池是否存在空闲线程
     * 2. 存在则使用
     * 3. 不存在,则创建线程 并放入线程池, 然后使用
     */
    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());
            }
        });


    }
}

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class Demo62 {
    public static void main(String[] args) {
        /**
         * 定长线程池.
         * (长度是指定的数值)
         * 执行流程:
         3. 单线程线程池
         4. 周期性任务定长线程池
         * 1. 判断线程池是否存在空闲线程
         * 2. 存在则使用
         * 3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用
         * 4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
         */
        ExecutorService service = Executors.newFixedThreadPool(2);
        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());
            }
        });


    }
}

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class Demo63 {
    public static void main(String[] args) {
        //效果与定长线程池 创建时传入数值1 效果一致.
        /**
         * 单线程线程池.
         * 执行流程:
         * 1. 判断线程池 的那个线程 是否空闲
         * 2. 空闲则使用
         * 4. 不空闲,则等待 池中的单个线程空闲后 使用
         */
        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());
            }
        });
    }
}

public static void main(String[] args) {
/**
 * 周期任务 定长线程池.
 * 执行流程:
 * 1. 判断线程池是否存在空闲线程
 * 2. 存在则使用
 * 3. 不存在空闲线程,且线程池未满的情况下,则创建线程 并放入线程池, 然后使用
 * 4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
 *
 * 周期性任务执行时:
 * 定时执行, 当某个时机触发时, 自动执行某任务 .
 */
        ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
/**
 * 定时执行
 * 参数1. runnable类型的任务
 * 参数2. 时长数字
 * 参数3. 时长数字的单位
 */
/*service.schedule(new Runnable() {
@Override
public void run() {
System.out.println("俩人相视一笑~ 嘿嘿嘿");
}
},5,TimeUnit.SECONDS);
*/
/**
 * 周期执行
 * 参数1. runnable类型的任务
 * 参数2. 时长数字(延迟执行的时长)
 * 参数3. 周期时长(每次执行的间隔时间)
 * 参数4. 时长数字的单位
 */
        service.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
        System.out.println("俩人相视一笑~ 嘿嘿嘿");
        }
        },5,2,TimeUnit.SECONDS);
        }

Lambda表达式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蜗牛变单车

您的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值