Java 多线程知识点

Java多线程知识点

线程与进程
多线程技术概述

进程与线程
进程:是指一个内存中运行的应用程序,每个进程都有一个独立的内存空间。
线程:是进程中的一个执行路径,共享一个内存空间,线程之间可以自由切换,并发执行,一个进程最少有一个线程。
县城实际上是在进程基础之上的进一步划分,一个进程启动之后,里面的若干执行路径有空也i划分成若干个线程。

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

并发与并行
并发:指两个或多个时间在同一时间段内发生
并行:同时执行

继承Thread

Ctrl+P:查看方法参数
Ctrl+Q:查看类、方法、属性注释

每个线程都拥有自己的栈空间,共用一份堆内存
由一个线程执行的方法,

public class day528 {
    public static void main(String[] args) {
        MyThread my = new MyThread();
        my.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("开启的线程"+i);
        }
    }
}
public class MyThread extends Thread{//继承Thread类

    /**
     * run方法就是线程要执行的任务方法
     */
    @Override
    public void run() {
       //这里的代码,就是一条新的执行路径
        //这个执行路径的触发方式,不是调用run方法,而是通过thread对象的start()来启动任务

        //  调用父类 super.run();
        for (int i = 0; i < 10; i++) {
            System.out.println("主线程main"+i);
        }
    }
}

输出结果:

主线程main0
开启的线程0
主线程main1
开启的线程1
主线程main2
开启的线程2
主线程main3
开启的线程3
主线程main4
开启的线程4
主线程main5
开启的线程5
主线程main6
开启的线程6
主线程main7
开启的线程7
主线程main8
开启的线程8
主线程main9
开启的线程9

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oANlGOCW-1623171979737)(C:\Users\Sang\AppData\Roaming\Typora\typora-user-images\image-20210528141557386.png)]

继承Thread 的匿名内部类

public class Demo2 {
    public static void main(String[] args) {
        new Thread(){ //匿名内部类,创建一个类,没定义(名称),但指定父Thread
            @Override
            public void run() {//重写run方法
                for (int i = 0; i < 10; i++) {
                    System.out.println("匿名内部类" + i);
                }
            }
        }.start();//并且 创建了对象 调用一次start()方法 通过匿名内部类 实现了一个线程 还是继承Thread
        for (int i = 0; i < 10; i++) {
            System.out.println("main方法"+i);
        }
    }
}
Thread类(不管是通过继承Thread或者实现Runnable 都需要使用Thread类)
实现Runnable
public class Demo3 {
    public static class MyRunnable implements Runnable{
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                System.out.println("用于给线程执行的任务"+i);
            }
        }
    }
    /**
     * //实现Runable 与 继承Thread相比有如下优势:
     * 1.通过创建任务的方式,然后给线程分配的方式,来实现的多线程
     *           更适合多个线程同时执行相同任务的情况
     * 2.避免继承所带来的局限性  Java 单继承 多实现
     * 3.任务与线程本身是分离的,提高了程序的健壮性。
     * 4.后续学习的线程池技术,接受Runnable类型的人五,不接受Thread类型的线程
     */
    public static class Demo {
        public static void main(String[] args) {
            MyRunnable mr = new MyRunnable();

            Thread t = new Thread(mr);
            t.start();
            for (int i = 0; i < 10; i++) {
                System.out.println("main方法"+i);
            }
        }
    }
}
设置和获取线程名称

currentThread //获取当前正在执行的线程对象(Thread)

getName() //获取线程名称

public static void main(String[] args) {
    System.out.println(Thread.currentThread().getName());
    new Thread(new MyRunable()).start();
}
static class MyRunable implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
线程休眠Sleep
public static void main(String[] args) throws InterruptedException {
    for (int i = 0; i < 10; i++) {
        System.out.println(i);
        Thread.sleep(1000);  //long millis 毫秒                                                            int nanos   纳秒
    }
}

输出结果:每隔1000ms 打印0-9 .

线程阻塞

常见的文件读取,接收用户输入 //耗时操作

线程中断

一个线程是一个独立的执行路径,它是否应该结束,应该有其自身决定。

public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(new MyRunable());
    t1.start();
    for (int i = 0; i < 5; i++) {
        System.out.println(Thread.currentThread().getName()+":"+i);
        Thread.sleep(1000);

    }t1.interrupt();
}
static class MyRunable 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) {
                System.out.println("main进程已中断");
                return; //加return 结束main和 run(),不加只中断main
            }
        }
    }
}

输出结果:

main:0
Thread-0:0
Thread-0:1
main:1
Thread-0:2
main:2
main:3
Thread-0:3
Thread-0:4
main:4
Thread-0:5
main进程已中断
守护线程

线程: 分为 守护线程 和 用户线程
用户线程:当一个进程不包含任何的存活的用户线程时,进行结束。

守护线程:守护用户线程的。当最后一个用户线程结束时,所有守护线程自动死亡。

public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(new MyRunable());
    t1.setDaemon(true);
    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();
        }
    }
    t1.interrupt();
}
static class MyRunable 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) {
                return;
                 //加return 结束main和 run(),不加只中断main
            }
        }
    }
}

输出结果:

main:0
Thread-0:0
Thread-0:1
main:1
Thread-0:2
main:2
Thread-0:3
main:3
Thread-0:4
main:4
Thread-0:5
线程安全问题
线程安全1-同步代码块

格式: synchronized(锁对象){

​ }

public static void main(String[] args) throws InterruptedException {
    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;//10张票
    private Object o = new Object();//将整个任务放进一个属性o里,即三个线程运行一个任务o,即一个锁
    @Override
    public void run() {

        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;
                }
            }
        }
    }
}

输出结果:

出票中
Thread-0出票成功!  余票:9
出票中
Thread-0出票成功!  余票:8
出票中
Thread-0出票成功!  余票:7
出票中
Thread-0出票成功!  余票:6
出票中
Thread-2出票成功!  余票:5
出票中
Thread-1出票成功!  余票:4
出票中
Thread-1出票成功!  余票:3
出票中
Thread-1出票成功!  余票:2
出票中
Thread-1出票成功!  余票:1
出票中
Thread-1出票成功!  余票:0

Process finished with exit code 0

线程安全2-同步方法
public static void main(String[] args) throws InterruptedException {
    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;//10张票
    //private Object o = new Object();//将整个任务放进一个属性o里,即三个线程运行一个任务o,即一个锁
    @Override
    public void run() {
        while (true) {
            boolean flag = sale();
            if (!flag){// 返回的是false
                break;
            }
        }
    }
    public synchronized boolean sale(){
        if (count > 0) {
            System.out.println("出票中");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count--;
            System.out.println(Thread.currentThread().getName() + "出票成功!  余票:" + count);
        }else{
            return false;
        }
        return true;
    }
}

输出结果:

出票中
Thread-0出票成功!  余票:9
出票中
Thread-0出票成功!  余票:8
出票中
Thread-0出票成功!  余票:7
出票中
Thread-0出票成功!  余票:6
出票中
Thread-0出票成功!  余票:5
出票中
Thread-0出票成功!  余票:4
出票中
Thread-0出票成功!  余票:3
出票中
Thread-0出票成功!  余票:2
出票中
Thread-0出票成功!  余票:1
出票中
Thread-0出票成功!  余票:0
公平锁与非公平锁

公平锁:线程排队执行
private Lock l = new ReentrantLock(true); // Lock 显示锁, fair 参数 为 true,就是公平锁

非公平锁:线程抢

public static void main(String[] args) throws InterruptedException {
    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;//10张票
    //private Object o = new Object();
    // 将整个任务放进一个属性o里,即三个线程运行一个任务o,即一个锁
    private Lock l = new ReentrantLock(true);//fair参数为true,就是公平锁
    @Override
    public void run() {
        while (true) {
            l.lock();
            boolean flag = sale();
            if (!flag){// 返回的是false
                break;
            }
        }
    }
    public synchronized boolean sale(){
        if (count > 0) {
            System.out.println("出票中");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count--;
            System.out.println(Thread.currentThread().getName() + "出票成功!  余票:" + count);
        }else{
            return false;
        }
        return true;
    }
}
线程死锁
 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);
        }
    }
//为了能在main方法里使用,加上静态static内部类修饰

    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("罪犯放了人质,警察放了罪犯");
        }
    }

输出结果:(锁了)

罪犯:你放我,我放人质
警察:你放人质,我放了你
多线程通信问题
生产者与消费者
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.setNameAndTaste("油泼面","麻辣味");
                }else {
                    f.setNameAndTaste("土豆粉","五香味");
                }
            }
        }
    }
    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++) {
                if (i%2==0){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    f.setNameAndTaste("油泼面","麻辣味");

                }else {
                    f.setNameAndTaste("土豆粉","五香味");
                }
                f.get();
            }
        }
    }
    static class Food{
        private String name;
        private String taste;
        private boolean flag = true;

        public synchronized void setNameAndTaste(String name,String taste) {
            if(flag) {
                this.name = name;
                try {
                    Thread.sleep(1000);
                } 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) { //false
                System.out.println("服务员端走的菜的名称是:" + name + "口味是:" + taste);
                flag = true;
                this.notifyAll();//唤醒厨师
                try {
                    this.wait();//服务员睡眠
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

输出结果:

服务员端走的菜的名称是:油泼面口味是:麻辣味  x50
服务员端走的菜的名称是:土豆粉口味是:五香味  x50
线程的六种状态

new: 表示线程刚被创建,没有启动的线程状态

Runnable: 在Java虚拟机中执行的线程状态

Blocked: 阻塞状态(线程排队执行时的状态)

Waiting: 无限期等待另一个线程执行特定操作的状态(线程休眠)

TimeWaiting:即时等待的状态(也可以被唤醒)

Trminated: 线程死亡,已退出的线程状态

带返回值的线程Callable
static class MyCallable implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            for (int i = 0; i < 10; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(i);
            }
            return 100;
        }
    }
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Integer> c = new MyCallable();
        FutureTask<Integer> f = new FutureTask<>(c);
        new Thread(f).start();
        Integer Int = f.get();//获取返回值时,会导致线程停止,直到获取返回值
        System.out.println("返回值为:"+Int);
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(i);
        }
    }

输出结果:

0
1
2
3
4
5
6
7
8
9
返回值为:100
0
1
2
3
4
5
6
7
8
9
线程池 Executors
概述:

如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程

就会大大降低 系统的效率,因为频繁创建线程和销毁线程需要时间. 线程池就是一个容纳多个线程的容

器,池中的线程可以反复使用,省去了频繁创建线程对象的操作,节省了大量的时间和资源。

Java中的四种线程池 .

无论是缓存线程池、定长线程池、单线程线程池,最终获取类型 都是ExecutorService

ExecutorService
1. 缓存线程池
public static void main(String[] args) {
        //newCachedThreadPool(); 创建缓存的线程的池
        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()+"不积硅步");
            }
        });
    }

输出结果:

   
pool-1-thread-1不积硅步
pool-1-thread-2不积硅步
pool-1-thread-3不积硅步
pool-1-thread-3不积硅步  // 使用的是缓存池里的线程,而不是线程4

2.定长线程池
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() {
                System.out.println(Thread.currentThread().getName()+"不积硅步");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
        service.execute(new Runnable() {
            @Override
            public void run() {

                System.out.println(Thread.currentThread().getName()+"不积硅步");
            }
        });
    }
}

输出结果:

pool-1-thread-2不积硅步
pool-1-thread-1不积硅步
pool-1-thread-1不积硅步

3.单线程线程池
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()+"不积硅步");
            }
        });
    }

输出结果:

pool-1-thread-1不积硅步
pool-1-thread-1不积硅步
pool-1-thread-1不积硅步
4.周期定长线程池:
public static void main(String[] args) {

        ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
       /* *//*
        定时执行一次
        参数1:定时执行的任务
        参数2:时长数字
        参数3:时长数字的时间单位TimeUnit的常量指定
         *//*
        service.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"无以至千里");
            }
        },5, TimeUnit.SECONDS);*/

        /*
        周期性执行任务  根据某个周期固定执行参数
        参数1:任务
        参数2:延迟时长数字(第一次执行在什么时间以后)
        参数3:周期时长数字 (每间隔多久执行一次)
        参数4:时长数字的单位
         */
        service.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("2秒过去了");
            }
        },5,2,TimeUnit.SECONDS);
    }

输出结果:

2秒过去了   //每间隔2s ,输出“2秒过去了”
2秒过去了
2秒过去了
2秒过去了
2秒过去了
2秒过去了
Lambad表达式

函数式编程思想
在代码上即把匿名内部类的 类的部分 删掉,保留一个抽象方法参数部分和方法体

范例1:
 /*
    Lambda表达式
    函数式编程思想
    面向对象: 创建对象调用方法,解决问题

     */
public static void main(String[] args) {
    //冗余的Runnable代码
    /*Thread t = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("无以至千里");
        }
    });
    t.start();*/

输出结果:

Thread-0无以至千里
Lambda 表达式写法
    Thread t = new Thread(()-> {
        System.out.println(Thread.currentThread().getName()+"无以至千里");
    });
    t.start();
}

输出结果:

Thread-0无以至千里
范例2:
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);

    }

    public static void main(String[] args) {
        print(new MyMath() {
            @Override
            public int sum(int x, int y) {
                return x+y;
            }
        },100,200);
    }

输出结果:

300
Lambda 表达式写法
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);
    }
    public static void main(String[] args) {
        print((int x, int y) ->{
                return x+y;
        },100,200);
    }

输出结果:

300
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值