Java多线程基础

#博学谷IT学习技术支持#

0.什么是多线程?

1.那什么是并发?什么是并行呢?

2.什么是进程?什么是线程?

3.Java中实现多线程有三种实现方式。三种!三种!三种!

3.1 继承Thread类

3.2第二种是实现Runnable接口

3.3 Callable

3.4 线程的一些属性

4.经典窗口售票问题

4.1 正确示例  --Runnable 实现

4.2 错误示例 --Thread实现

4.3 同步方法实现

4.4 lock锁实现--ReentrantLock

5.写个死锁(面试题)

6.老八吃汉堡(线程等待和线程唤醒机制)

7.阻塞队列

8.线程的状态(6种)


0.什么是多线程?

比如你边打游戏边和女朋友电话,你的大脑cpu 就是开了两个线程,最后会怎么样,大脑过载,游戏输了,女朋友跑了。

1.那什么是并发?什么是并行呢?

并发:你边打游戏,边和你女朋友打电话,这个行为呢就是并发,因为只有一个大脑,这两件事肯定是交替进行的,所以你女朋友会生气。

并行:你打游戏,我来陪你女朋友打电话,那么我和你的行为就是并行,因为有两个大脑,这两件事不会冲突。

2.什么是进程?什么是线程?

你开个游戏呢就是一个进程,在游戏里走位,放技能,就是不同的线程

3.Java中实现多线程有三种实现方式。三种!三种!三种!

3.1 继承Thread类

线程开启是  start()  方法 重写的方法类是 run()

public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"我是一个大帅哥!");
        }
    }
    public static void main(String[] args) {
        //继承了线程类之后呢,该类呢也就变为一个线程类,你每new一个对象那么就是一个线程
        MyThread thread = new MyThread();
        MyThread thread1 = new MyThread();
        //线程启动,启动了不能重复启动,除非该线程停止之后
        thread.start();
        thread1.start();

        //thread.run()和thread.start()的区别就是线程名字不一样。 
        //Thread.currentThread().getName()
    }
}

3.2第二种是实现Runnable接口

public class MyRunable implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"我是一个无敌大帅哥!");
    }

    public static void main(String[] args) {
        MyRunable myRunable = new MyRunable();
        //这边需要说明的是Thread自己本身也实现了Runnable接口
        Thread mythread = new Thread(myRunable);
        mythread.start();
    }
}

3.3 Callable<Object>

//Callable<String>这边的String是返回值的类型
public class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        for (int i = 0; i <10 ; i++) {
            System.out.println("我疯狂的E");
        }
        return "面对疾风吧!";
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //任务的容器
        MyCallable myCallable = new MyCallable();
        //接收返回值的容器
        FutureTask<String> futureTask = new FutureTask<>(myCallable);
        //线程
        Thread thread = new Thread(futureTask);
        thread.start();
        System.out.println(futureTask.get());
    }
}

3.4 线程的一些属性

Thread thread1 = new Thread(futureTask1);
        thread1.setName("yasuo");
//线程的优先级越高,那么先执行的概率越高,并不是百分之百抢占
        thread1.setPriority(3);
//线程有两种调度,分时调度和抢占调度。java里面是抢占调度
//设置成守护进程,如果别的线程执行完了,那么这个线程也就结束
        thread1.setDaemon(true);

4.经典窗口售票问题

4.1 正确示例  --Runnable 实现

public class Ticket12307 implements Runnable{
    private int num = 100;
    private Integer a = 0;
    @Override
    public void run() {

        //这边的循环就是当作一个不停的程序
        while(true){
            //这边必须是对象 int 不行
            //这边需要注意的是代码块这这边的a必须是同一个对象,我多个线程不能个拿各的a,可以看下面调用
            //实际上操作的是一个对象,这个a可以没有实际的意义,可以理解为谁抢到了a的使用权,就可以执行下面的
            //代码块的代码。
            //思考一下这边a改成this行不行?
            synchronized (a){
                if(num>0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    num--;

                    System.out.println(Thread.currentThread().getName()+"还剩"+num);

                }else{
                    System.out.println("没票了!");
                    break;
                }
            }
        }

    }

    public static void main(String[] args) {
        //这边操作的是一个对象
        //用三个线程去调用了
        //下面我会举一个不同的例子就是自己用自己的锁
        //需要注意的是这便是用Runnable实现的下面用Thread来实现
        Ticket12307 ticket12307 = new Ticket12307();
        Thread one = new Thread(ticket12307);
        Thread two = new Thread(ticket12307);
        Thread three = new Thread(ticket12307);
        one.setName("窗口1");
        two.setName("窗口2");
        three.setName("窗口3");
        one.start();
        two.start();
        three.start();

    }
}

4.2 错误示例 --Thread实现

public class Ticket12308 extends Thread{
    //这边关注一下,为什么加static 因为多线程关系,会创建多个类;
    //如果不创建static 那么num就会有多个,操作的不是同一个对象就没有意义了
    private static int num = 100;

    private static Integer b = 100;
    @Override
    public void run() {
        while(true){
            //这边的this 指的就是Ticket12308这个对象,new多个很显然不是一个对象
            //这边修改的话必须使用同一个对象
            //synchronized (b) 这个是正确的
            synchronized (this){//这个是错误的。思考一下synchronized (Ticket12308.class)行不行
                if(num>0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    num--;

                    System.out.println(Thread.currentThread().getName()+"还剩"+num);

                }else{
                    System.out.println("没票了!");
                    break;
                }
            }
        }
    }

    public static void main(String[] args) {
        //注意这边是new了两个对象那么关注一下上面同步代码块里的this,你觉得两个线程是同一个this吗?
        Ticket12308 ticket12308 = new Ticket12308();
        Ticket12308 ticket12308Two = new Ticket12308();
        ticket12308.start();
        ticket12308Two.start();
    }
}

4.3 同步方法实现

public class Ticket12309 implements Runnable{

    private static int num = 100;

    @Override
    public void run() {
        while(true){
            if(SellTickets()){
                break;
            }
        }
    }
    //这边是用同步代码块,这个也相当于synchronized(this),是在Runnable中实现是可以的,Thread是不行的
    private synchronized boolean SellTickets(){
        if(num>0){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            num--;

            System.out.println(Thread.currentThread().getName()+"还剩"+num);
            return false;
        }else{
            System.out.println("没票了!");
            return true;
        }
    }

    public static void main(String[] args) {
        Ticket12309 ticket12309 = new Ticket12309();
        Thread one = new Thread(ticket12309);
        Thread two = new Thread(ticket12309);
        Thread three = new Thread(ticket12309);
        one.setName("窗口1");
        two.setName("窗口2");
        three.setName("窗口3");
        one.start();
        two.start();
        three.start();

    }
}

4.4 lock锁实现--ReentrantLock

import java.util.concurrent.locks.ReentrantLock;

public class Ticket12305 implements Runnable{
    private int num = 100;
    private ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {

        while(true){
            //开启锁
            lock.lock();
            try {
                if(num>0){
                    Thread.sleep(100);
                    num--;
                    System.out.println(Thread.currentThread().getName()+"还剩"+num);

                }else{
                    System.out.println("没票了!");
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //释放锁
                lock.unlock();
            }
        }

    }

    public static void main(String[] args) {
        Ticket12305 ticket12305 = new Ticket12305();
        Thread one = new Thread(ticket12305);
        Thread two = new Thread(ticket12305);
        Thread three = new Thread(ticket12305);
        one.setName("窗口1");
        two.setName("窗口2");
        three.setName("窗口3");
        one.start();
        two.start();
        three.start();

    }
}

5.写个死锁(面试题)


//锁嵌套产生的死锁
public class MyDeadLock {
    public static void main(String[] args) {
        Integer a = 10;
        Integer b = 20;
        new Thread(()->{
            //这边的while 模拟一直有请求
            while(true){
                synchronized (a){
                    synchronized (b){
                        System.out.println("我出来了!!!!问僧特");
                    }
                }
            }
        }).start();

        new Thread(()->{
            //这边的while 模拟一直有请求
            while (true){
                synchronized (b){
                    synchronized (a){
                        System.out.println("我出来了!!!!德莱文");
                    }
                }
            }
        }).start();
    }
}

6.老八吃汉堡(线程等待和线程唤醒机制)

重要的不是代码本身,重要的是想一下不加锁,会产生什么情况

这边只有两个线程,唤醒就是唤醒对方

public class OldEightEatHanBaoBao {
    //做八个,吃八个
    static int num = 8;
    //做一个吃一个,hava 表示现在做好了没
    static boolean have = false;
    static Integer lock = 0;
    public static void main(String[] args) {
        //老八做汉堡的线程
        new Thread(()->{
            //这边一直做,做够8个汉堡就结束
            while(true){
                synchronized (lock){
                    if(num==0){
                        //做完了
                        System.out.println("全部做完了");
                        break;
                    }else{
                        if(!have){
                            have =true;
                            System.out.println("老八蜜汁小汉堡!"+num);
                            num--;
                            //这边唤醒所有在这把锁等待的线程
                            //lock.notifyAll();
                            lock.notify();
                        }else{
                            try {
                                //这边的线程等待状态必须用当前锁对象才可以进行等待
                                lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }).start();
        //老八吃汉堡
        new Thread(()->{
            //这边一直吃,全部吃完就停止
            while(true){
                synchronized (lock){
                    if(have){
                        System.out.println("吃完了害嗨害!");
                        have =false;
                        //lock.notifyAll();
                        lock.notify();
                    }else{
                        if(num==0){
                            System.out.println("全部吃完了");
                            break;
                        }else{
                            try {
                                lock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }

                    }
                }
            }
        }).start();

    }
}


7.阻塞队列

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class Quene {
    public static void main(String[] args) throws InterruptedException {
        //这边阻塞队列就是用锁做的,取不到就会一直等待
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(5);
        //LinkedBlockingQueue queueOne = new LinkedBlockingQueue();
        queue.put("1");
        System.out.println(queue.take());
        queue.take();//如果去不到就会等待。
    }
}

8.线程的状态(6种)

线程状态标识线程状态出现时间点
NEW新建状态new Threa() 还没有start的时候
RUNNABLE就绪状态start() 之后cpu调度到了就是运行态,没调度到就是就绪态
BLOCKED阻塞状态遇到了锁,有其他线程先拿到了锁,等锁释放的过程就是阻塞状态
WAITING等待状态wait() 方法调用之后的状态
TIMED_WAITING有时间的等待状态sleep()
TERMINATED死亡状态线程内定义的方法也就是run()里的方法执行完成之后
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值