Java多线程

一、线程:

线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位

简单理解:应用软件中互相独立,可以同时运行的功能

并发:在同一时刻,有多个指令在单个CPU上交替 执行

并行:在同一时刻,有多个指令在多个CPU上同时执行

二、多线程的实现方式:

①继承Thread类的方式进行实现

代码演示:

package a01threaddemo;

public class MyThread extends Thread{
    public void run(){
        for (int i = 0; i < 100; i++) {
            System.out.println(getName()+"hello world");
        }
    }
}

测试类:

package a01threaddemo;

public class ThreadDemo1 {
    public static void main(String[] args) {
        //多线程的第一种启动方式
        //1.自己定义一个类继承Thread
        //2.重写run方法
        //3.创建子类的对象,并启动线程
        MyThread t1=new MyThread();
        MyThread t2=new MyThread();
        t1.setName("线程1");
        t2.setName("线程2");
        //开启线程用start
        t1.start();
        t2.start();//两个线程交替执行
    }
}

 运行结果:

②实现Runnable接口的方式进行实现

代码演示:

package a01threaddemo;

public class MyRun implements Runnable{
    @Override
    public void run() {
        //书写线程要执行的代码
        for (int i = 0; i < 100; i++) {
            //获取到当前线程的对象
         /*   Thread t=Thread.currentThread();
            System.out.println(t.getName()+"helloWorld");
            */
            System.out.println(Thread.currentThread().getName()+"helloWorld");
        }
    }
}

测试类:

package a01threaddemo;

public class ThreadDemo2 {
    public static void main(String[] args) {
        //多线程第二种启动方式
        //1.自己定义一个类实现Runnable接口
        //2.重写里面的run方法
        //3.创建自己的类的对象
        //4.创建一个Thread类的对象,并开启线程

        //创建MyRun的对象
        //表示多线程要执行的任务
        MyRun mr=new MyRun();
        //创建线程对象
        Thread t1=new Thread(mr);
        Thread t2=new Thread(mr);

        //给线程设计名字
        t1.setName("线程1");
        t2.setName("线程2");
        //开启线程
        t1.start();
        t2.start();
    }
}

运行结果:两个线程交替执行

 

 ③利用Callable接口和Future接口方式实现

代码演示:

package a01threaddemo;

import java.util.concurrent.Callable;

public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        //求1~100之间的和
        int sum=0;
        for (int i = 1; i <= 100; i++) {
            sum=sum+i;
        }
        return sum;
    }
}

运行结果:

package a01threaddemo;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

public class ThreadDemo3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //多线程的第三种方式
        //特点:可以获取到多线程运行的结果
        //1.创建一个类MyCallable实现Callable接口
        //2.重写call(是有返回值的,返回值表示多线程的运行结果)
        //3.创建MyCallable的对象(表示多线程要执行的任务)
        //4.创建FutureTask的对象(作用:管理多线程运行的结果)
        //5.创建Thread的对象(表示线程)

        MyCallable mc=new MyCallable();
        FutureTask<Integer> ft=new FutureTask<>(mc);
        Thread t1=new Thread(ft);
        t1.start();
        Integer result = ft.get();
        System.out.println(result);

    }
}

三、常见的成员方法: 

1. 前4个代码演示:
package a02threaddemo;

public class MyThread extends Thread{
    public MyThread() {
    }

    public MyThread(String name) {
        super(name);
    }

    public void run(){
        for (int i = 0; i < 100; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(getName()+"@"+i);
        }
    }
}

测试类:

package a02threaddemo;

public class ThreadDemo1 {
    public static void main(String[] args) throws InterruptedException {
        //细节1:如果没有给线程设置名字,线程也是有默认的名字的
        //格式:Thread-X(X序号,从0开始的)
        //细节2:如果我们要给线程设置名字,可以用set方法进行设置,也可以用构造方法进行设置
        //细节3:当JVM虚拟机启动之后,会自动的启动多条线程,其中有一条线程就叫做main线程
        //他的作用就是去调用main方法,并执行里面的代码
        //在以前,我们写的所有的代码都是运行在main线程中的
        //sleep:让线程休眠
        //细节1:哪条线程执行到这个方法,哪条线程就会在这里停留对应的时间
        //细节2:方法的参数:就表示睡眠的时间,单位毫秒
        //细节3:当时间到了之后,线程会自动的醒来,继续执行下面的其他代码



        //1.创建线程的对象
        MyThread t1=new MyThread("线程1");
        MyThread t2=new MyThread("线程2");
        //2.开启线程
        t1.start();
        t2.start();


     /*   Thread t=Thread.currentThread();
        String name = t.getName();
        System.out.println(name);
        */

    /*    System.out.println("1111111111111");
        Thread.sleep(5000);
        System.out.println("222222222");
     */

    }
}
2.线程的优先级:分为抢占式调度和非抢占式调度

Java中是抢占式调度(随机性) 

代码演示:

package a02threaddemo;

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println(Thread.currentThread().getName()+"---"+i);
        }
    }
}

 测试类:

package a02threaddemo;

import a01threaddemo.MyRun;

public class ThreadDemo2 {
    public static void main(String[] args) {
        MyRunnable mr=new MyRunnable();
        Thread t1=new Thread(mr,"线程1");
        Thread t2=new Thread(mr,"线程2");
//        System.out.println(t1.getPriority());//5
//        System.out.println(t2.getPriority());//默认优先级是5,最小是1,最大是10
//        System.out.println(Thread.currentThread().getPriority());//5
        t1.setPriority(1);
        t2.setPriority(10);
        //优先级越高抢占到CPU的概率越大
        t1.start();
        t2.start();
    }
}

运行结果:

 

 3.守护线程:

细节:当其他的非守护线程执行完毕后,守护线程会陆续结束(并不会执行完所有代码就结束了)

四、 生产者和消费者(常见方法)

void wait()--------->当前线程等待,直到被其他线程唤醒

void notify()-------->随机唤醒单个线程

void notifyAll()-------->唤醒所有线程

等待唤醒机制代码演示

厨师类:

package a03threaddemo;

public class Cook extends Thread {
    public void run() {
        while (true) {
            synchronized (Desk.lock) {
                if (Desk.count == 0) {
                    break;
                } else {
                    //判断桌子上是否有食物
                    if (Desk.foodFlag == 1) {
                        //如果有就等待
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    } else {
                        //如果没有就制作食物
                        System.out.println("厨师做了一碗面条");
                        //修改桌子上的食物状态
                        Desk.foodFlag = 1;
                        //唤醒等待的消费者开吃
                        Desk.lock.notifyAll();
                    }
                }
            }
        }
    }
}

吃货类:

package a03threaddemo;

public class Foodie extends Thread{
    public void run(){
        //步骤:
        //1.循环
        //2同步代码块
        //3.判断共享数据是否到了末尾(先写到了末尾因为简单)
        //4.没有到末尾情况,执行核心逻辑

        while(true){
            synchronized (Desk.lock){
                if(Desk.count==0){
                    break;
                }else{
                    //先判断桌子上是否有面条
                    if(Desk.foodFlag==0) {
                        //如果没有就等待
                        try {
                            Desk.lock.wait();//让当前线程跟锁进行绑定
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }else {
                        //把吃的总数-1
                        Desk.count--;
                        //如果有就开吃
                        System.out.println("吃货正在吃面条,还能再吃" + Desk.count + "碗!!!");
                        //吃完之后唤醒厨师继续做
                        Desk.lock.notifyAll();//唤醒绑定这把锁的所有线程
                        //修改桌子的状态
                        Desk.foodFlag = 0;
                    }
                }
            }
        }
    }
}

桌子类:

package a03threaddemo;

public class Desk {
    //控制生产者和消费者的执行
    //foodFlag 0:没有面条  1:有面条
    //boolean只能控制两条线程,所以如果以后线程变多了,就不能用了
    public static int foodFlag=0;
    //总个数:
    public static int count=10;
    //锁对象
    public static Object lock=new Object();
}

测试类:

package a03threaddemo;

public class ThreadDemo2 {
    public static void main(String[] args) {
        //创建线程对象
        Cook c=new Cook();
        Foodie f=new Foodie();
        //给线程设计名字
        c.setName("厨师");
        f.setName("吃货");
        c.start();
        f.start();

    }
}

运行结果:

 

 等待唤醒机制(阻塞队列方式实现)

生产者和消费者必须使用同一个阻塞队列

厨师类:

package a04threaddemo;

import java.util.concurrent.ArrayBlockingQueue;

public class Cook extends Thread{
    ArrayBlockingQueue<String> queue;

    public Cook(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }

    public void run(){
        while(true){
            //不断的把面条放在阻塞队列当中
            try {
                queue.put("面条");
                System.out.println("厨师放了一碗面条");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

 吃货类:

package a04threaddemo;

import java.util.concurrent.ArrayBlockingQueue;

public class Foodie extends Thread{
    ArrayBlockingQueue<String> queue;

    public Foodie(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }
    public void run(){
        while(true){
            //不断的从阻塞队列中获取面条
            //不用写锁,代码底层有锁
            try {
                String food = queue.take();
                System.out.println(food);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

测试类:

package a04threaddemo;

import java.util.concurrent.ArrayBlockingQueue;

public class ThreadDemo {
    public static void main(String[] args) {
        //1.创建阻塞队列的对象
        ArrayBlockingQueue<String> queue=new ArrayBlockingQueue<>(1);
        //2.创建线程的对象,并把阻塞队列传递过去
        Cook c=new Cook(queue);
        Foodie f=new Foodie(queue);
        c.start();
        f.start();
    }
}

运行结果:会死循环

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值