Java多线程

一、线程

1.1 并发与并行的概念(重点)

  1. 程序: 一个固定逻辑与数据的集合就是程序 例如 俄罗斯方块 贪吃蛇
  2. cpu: 中央处理器 主要用于协调程序与硬件的工作
  3. 并发与并行
    • 并发(高并发): 在同一一个时间段 执行两个 或者多个程序的 单核cpu 交互的执行 由于cpu切换的速度比较块
      可能产生的误区 是同时执行 是交替执行
    • 并行:在同一个时刻 执行两个或者是多个程序的时候 多核cpu 同时执行 目前电脑都是多核的cpu
      例子:看小电影 听音乐 例子:玩游戏 键盘侠

1.2 进程与线程(了解)

1. 进程:运行在内存中的程序就是进程 例子:idea   百度网盘   画图的工具
2. 线程:通向cpu的执行的路径就是线程
3. 线程分类:单线程与多线程
   		单线程: 只有一条通向cpu的执行的路径 就是单线程
   		多线程: 多条通向cpu的执行的路径 就是多线程

1.4 线程的五种状态

  1. 新建状态
  2. 就绪状态
  3. 阻塞状态/等待/睡眠
  4. 运行状态
  5. 死亡状态

1.3 创建线程的方式

1.3.1 继承Thread类

步骤:

  1. 定义一个类继承Thread
  2. 重写run()方法 执行线程的操作
  3. 实例化这个线程类的对象
  4. 调用start() 方法 开启线程
1.3.2 实现Runnable接口(重点)

步骤:

1. 定义一个类 实现 Runnable
2. 重写run()方法
3. 实例化线程对象 Thread    传递一个参数 Runnable 的实现类
4. 通过Thread对象调用方法开启线程  start()
1.3.3 使用匿名内部类创建多线程(重点)
package com.ahao;
public class Test01 {
    public static void main(String[] args) {
        //第一种方式
         new Thread(new Runnable() {
             @Override
             public void run() {
                 System.out.println(Thread.currentThread().getName());
             }
         }).start();
         //第二种方式
        new Thread(){
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        }.start();
    }
}
1.3.4 实现Callable接口(重点)
1. 定义一个类实现接口 Callable
2. 重写call()方法
3. 实例化 任务对象 FutureTask  构建一个Callable的实现类
4. 实例化线程对象 Thread  构建一个任务对象
5. 开启线程
6. 调用任务对象的get() 获取其返回值

线程类代码:

import java.util.concurrent.Callable;

public class MyCallable implements Callable {
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            System.out.println(i);
            sum+= i;
        }
        return sum;
    }
}

测试类代码:

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

public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyCallable callable = new MyCallable();
        //实例化任务对象
        FutureTask<Integer> task = new FutureTask<>(callable);
        //构建任务对象
        new Thread(task).start();
        Integer sum = task.get();
        System.out.println("1+2+......+99+100="+sum);
    }
}
1.3.5 线程池

简介:用于来管理与维护线程

步骤:

1. 通过线程池的工具类来创建线程对象
2. 创建一个线程任务对象
3. 将任务对象提交线程池中
4. 通过get() 获取到线程执行完的结果

线程类代码1:

import java.util.concurrent.Callable;

public class MyCallable implements Callable {
    @Override
    public Object call() throws Exception {
        return Thread.currentThread().getName()+"\t"+"666";
    }
}

线程类代码2:

public class MyRunnable implements Runnable{
  @Override
  public void run() {
      System.out.println(Thread.currentThread().getName()+"\t"+"Runnable");
  }
}

测试类:

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

public class Test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService pool = Executors.newFixedThreadPool(2);//设置线程数量
        MyRunnable r1 = new MyRunnable();
        MyRunnable r2 = new MyRunnable();
        MyCallable callable = new MyCallable();
        Future future = pool.submit(callable);
        System.out.println(future.get());

        pool.submit(r1);
        pool.submit(r2);
        pool.submit(r1);
        pool.submit(r2);
        pool.submit(r1);
    }
}

二、线程中的方法(重要)

2.1 线程休眠

方法的名称方法 的描述
public static void sleep(long millis)public static void sleep(long millis)

2.2 守护线程

1. 守护线程:守护其它的线程  守护其它线程执行完操作  java中gc垃圾回收器 jav程序在运行期间 都会出现垃圾,这个九垃圾就是由gc来默默进行回收 gc就是一个守护的线程
2. 守护线程的死亡: 被守护的线程执行完操作 或者是死亡 那么守护线程也就是死亡
3. 一般守护线程都是守护主线程 
方法的名称方法的描述
public final void setDaemon(boolean on)设置为守护线程
public final boolean isDaemon()测试该线程是否为守护线程

2.3 线程的优先级

2.3.1 优先级常量
常量的名称常量的描述
public static final int MAX_PRIORITY线程可以具有的最高优先级
public static final int MIN_PRIORITY线程可以具有的最低优先级
public static final int NORM_PRIORITY分配给线程的默认优先级
    /**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;

注意点:

A.线程的最高优先级是10 线程的最低优先级是1 范围 1-10

B.线程优先级越高 表示获取cpu执行权越大 并不一定会执行 java 抢占式调度

2.3.2 方法
方法的名称方法的描述
public final int getPriority()返回的是线程的优先级
public final void setPriority(int newPriority)更改线程的优先级

2.4线程常用的方法(重点)

方法的名称方法的说明
public final void stop()强迫线程停止执行
public static void yield()暂停当前正在执行的线程对象,并执行其他线程(礼让)
public final void join()等待该线程终止(方法必须在线程开启之后进行调用)
2.4.1 stop的代码演示
package com.qf.demo03;

public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i=1;i<=10;i++){
            if (i==5){
                //终止线程
                stop();
            }
            System.out.println(i);
        }
    }
}

package com.qf.demo03;

public class Test01 {
    public static void main(String[] args) {
     //实例化线程对象
        MyThread t  = new MyThread();
        t.start();
    }
}

2.4.2 yield的代码演示
package com.qf.demo04;

public class MyThread extends  Thread {

    @Override
    public void run() {
        for (int i=0;i<100;i++){
            System.out.println(getName()+"\t"+i);

        }
    }
}

package com.qf.demo04;

public class Test01 {
    public static void main(String[] args) {
        MyThread t1= new MyThread();
        t1.yield();
        t1.start();
        MyThread t2 = new MyThread();
        t2.start();
    }
}

2.4.3 join 方法代码演示
package com.qf.demo05;

public class MyThread extends  Thread {

    @Override
    public void run() {
        for (int i=0;i<100;i++){
            System.out.println(getName()+"\t"+i);

        }
    }
}

package com.qf.demo05;

public class Test01 {
    public static void main(String[] args) throws InterruptedException {
        MyThread t1= new MyThread();
        t1.start();
        t1.join();
        MyThread t2 = new MyThread();
        t2.start();
    }
}

三、Object 提供操作线程的方法(重点)

3.1 方法的介绍

方法的名称方法的描述
public final void wait()无限等待(需要被唤醒)
public final void wait(long timeout)计时等待
public final void notify()唤醒在此对象监视器上等待的单个线程(一个)
public final void notifyAll()唤醒在此对象监视器上等待的所有线程(多个)

四、线程通信

4.1案例:

A.每一个窗口就是一个线程 使用线程来表示多窗口售票
B.数据共享 使用第二种方式来创建线程
C.定义一个变量来表示票数
D.循环售票

线程不安全案例代码:

public class MyRunnable implements Runnable{
    //定义一个变量来记录票数
    private  int  count=100;
    @Override
    public void run() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //使用循环一直买票
        while (true){
            if (count > 0) {
                System.out.println(Thread.currentThread().getName()+"\t"+"您购买是第"+count+"张票");
                count--;
            }
        }

    }
}

public class Test01 {
    public static void main(String[] args) {
        //实例化MyRunnable对象
        MyRunnable runnable = new MyRunnable();
        //实例化线程
        Thread t1 = new Thread(runnable);
        t1.start();
        //实例化线程
        Thread t2 = new Thread(runnable);
        t2.start();
        //实例化线程
        Thread t3 = new Thread(runnable);
        t3.start();

    }
}

4.2 第一种解决方案-同步代码块

1.语法:
    synchronized(锁对象) {
          可能产生问题的代码
    }
2.注意点
   A.锁的对象可以是任意的对象 
   B.所有线程锁的对象必须是同一个对象
3.作用:
    解决数据共享安全的问题

解决代码:

public class MyRunnable implements Runnable{
    //定义一个变量来记录票数
    private  int  count=100;
    //定义一个锁的对象
    private  Object obj  = new Object();
    @Override
    public void run() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //使用循环一直买票
        while (true){
            synchronized (obj) {
                if (count > 0) {
                    System.out.println(Thread.currentThread().getName()+"\t"+"您购买是第"+count+"张票");
                    count--;
                }
            }
        }

    }
}

4.3 第二种解决方案 -同步方法

1.语法:
  访问修饰符 synchronized  返回值类型  方法的名称(参数列表) {
        方法体
      retrun  返回值
  }
2.说明:同步方法可以是普通的成员方法   也可以是静态的方法
3.说明:
   A.成员方法的锁的对象就是this
   B.静态方法锁的对象是当前类的class对象

解决代码:

public class MyRunnable implements Runnable{
    //定义一个变量来记录票数
    private static int  count=100;
    @Override
    public void run() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //使用循环一直买票
        while (true){
            showInfo();         
        }
    }
   //同步方法
    public   static synchronized  void   showInfo() {
        if (count > 0) {
            System.out.println(Thread.currentThread().getName()+"\t"+"您购买是第"+count+"张票");
            count--;
        }
    }
}

4.4 第三种解决方案-锁

1.Lock 简介
 A.Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。
 B.此实现允许更灵活的结构
2. 实现类ReentrantLock
3.方法
方法的名称方法的描述
void lock()获取锁
void unlock()释放锁

解决代码:

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

public class MyRunnable implements Runnable{
    //定义一个变量来记录票数
    private  int  count=1000;
    //实例化Lock锁对象
    private Lock   l = new ReentrantLock();
    @Override
    public void run() {
        //获取锁对象
        l.lock();
        try {
            Thread.sleep(500);
            //使用循环一直买票
            while (true){

                    if (count > 0) {
                        System.out.println(Thread.currentThread().getName()+"\t"+"您购买是第"+count+"张票");
                       count--;
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            //释放锁对象
            l.unlock();
        }
    }
}
	

五、死锁

  1. 死锁: A占用B的锁对象 B占用的A的锁对象 互补谦让 两个线程都处于等待状态 出现了死锁

六、生产者与消费者模式(重点)

6.1简介:

生产者不能一直生产,消费者不能一直消费

​ 生产者生产产品 —> 等待消费者消费

​ 消费者购买完产品—>等待生产者生产

6.2 案例代码:

产品类:

public class BaoZi {
    public  String pi;
    public  String xian;
    //如果false 表示没有包子  为true表示有包子
    public  boolean  flag = false;
}

线程类-01:

public class MyThread01 extends Thread {
    private BaoZi baoZi;
    public MyThread01(BaoZi baoZi) {
        this.baoZi = baoZi;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (baoZi){
                try {
                    if (baoZi.flag) {
                        baoZi.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                baoZi.pi = "薄皮";
                baoZi.xian = "肉馅";
                System.out.println("生产了一个" + baoZi.pi + baoZi.xian + "的包子");
                baoZi.flag = true;
                baoZi.notify();
            }
        }

    }
}

线程类-02:

public class MyThread02 extends Thread {
    private BaoZi baoZi;
    public MyThread02(BaoZi baoZi) {
        this.baoZi = baoZi;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (baoZi){
                try {
                    if (!baoZi.flag) {
                        baoZi.wait();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("我吃了一个" + baoZi.pi + baoZi.xian + "的包子");
                baoZi.pi = null;
                baoZi.xian = null;
                baoZi.flag = false;
                baoZi.notify();
            }
        }

    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        BaoZi baoZi = new BaoZi();
        new MyThread01(baoZi).start();
        new MyThread02(baoZi).start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值