JavaDay16-多线程(一)

一、多线程

1、并发、并行

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

2、多任务、多线程

  • 多任务:很多任务一项一项的处理,一次一件
  • 多线程:同时处理多个线程,一次多件

3、程序、进程process、线程thread

  • 程序:就是写好的代码,是静态的
  • 进程:是指程序执行一次,是动态的。是系统资源分配的单位。一个进程可以有多个线程,因为一个程序中可以有多个方法。
  • 线程:是CPU执行的最小单位,一个进程可以有多个线程,一个main方法就是一个线程。

4、核心概念

  • 线程是独立的执行路径
  • 程序运行时,即使没有创建线程,后台也会有多个线程,如主线程(main)、gc线程
  • 如果一个进程中开辟了多个线程,那么线程的运行顺序是由调度器安排调度的,不能人为干预
  • 资源抢夺:对同一份资源进行操作,需要加入并发控制
  • 线程会带来额外的开销,如CPU调度、并发控制开销
  • 线程在自己的工作内存交互,如果内存控制不当会造成数据不一致。

二、创建线程的三种方法

1、继承Thread类

//多线程的第一种实现方式
/*
继承Thread类、重写run方法;
创建子类对象、调用start方法。
 */
public class ThreadDemo01 {
    public static void main(String[] args) {
        MyRun run1 = new MyRun();
        MyRun run2 = new MyRun();
        MyRun run3 = new MyRun();
        run1.setName("1");
        run2.setName("2");
        run3.setName("3");
        run1.start();
        run2.start();
        run3.start();
    }
}
//Demo01的MyRun
public class MyRun extends Thread{
    public void run(){
        for (int i = 0; i < 20; i++) {
            System.out.println(getName()+"多线程");
        }
    }
}

2、实现Runnable接口

//多线程的第二种实现方式
/*
实现runnable接口,重写run方法;
创建 实现了runnable接口 的对象;
创建Thread对象,调用start方法。
 */
public class ThreadDemo02 {
    public static void main(String[] args) {
        MyRun run = new MyRun();
        Thread thread1 = new Thread(run);
        Thread thread2 = new Thread(run);
        Thread thread3 = new Thread(run);
        thread1.setName("1");
        thread2.setName("2");
        thread3.setName("3");
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
//Demo02的MyRun
public class MyRun implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"多线程");
        }
    }
}

3、Callable接口+Future接口

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

//多线程的第三种实现方式
/*
1、创建多线程类,实现callable接口(泛型接口),重写call方法
2、创建多线程对象
3、创建FutureTask对象,管理多线程程序的运行结果
4、创建Tread对象,调用start方法
5、通过FutureTask对象,调用get方法,获取多线程程序的运行结果
 */
public class ThreadDemo03 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyRun myRun = new MyRun();
        //管理多线程程序运行的结果 泛型与多线程程序保持一致
        FutureTask<Integer> future = new FutureTask<>(myRun);
        Thread thread = new Thread(future);
        thread.start();
        Integer sum = future.get();
        System.out.println(sum);
    }
}
import java.util.concurrent.Callable;
//Demo03的MyRun
public class MyRun implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum=0;
        for (int i = 0; i < 100; i++) {
            sum +=i;
        }
        return sum;
    }

}

三、同步代码块、同步方法

1、同步代码块(卖票的例子)

//多个线程操作一个数据--卖票
//同步代码块
/*
问题:
1、不同对象共享数据
2、出现相同的票--cpu资源在运行过程中随时有可能被其他线程抢走
3、出现超出范围的票
解决:
同步代码块-把操作共享数据的代码锁起来
特点:
1、锁默认打开,有一个线程进去了,锁自动关闭
2、里面的代码全部执行完毕,线程出来,锁自动打开
 */
public class ThreadDemo04 {
    public static void main(String[] args) {
        SoldDemo soldDemo1 = new SoldDemo();
        SoldDemo soldDemo2 = new SoldDemo();
        SoldDemo soldDemo3 = new SoldDemo();
        soldDemo1.start();
        soldDemo2.start();
        soldDemo3.start();
    }
}
public class SoldDemo extends Thread{
    private static int ticket;//static表示这个类的所有对象都共享ticket数据
    //static关键字保证对象必须唯一
    static Object obj=new Object();
    @Override
    public void run() {
        while (true){
            //同步代码块
            synchronized (obj){//也可以是SoldDemo.class(保证对象这个参数是唯一的)
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                if (ticket<100){
                    System.out.println(Thread.currentThread().getName()+"第"+ticket+"张票");
                    ticket++;
                }else {
                    break;
                }
            }
        }
    }
}

2、同步方法(卖票的例子)

//卖票
//同步方法
public class ThreadDemo05 {
    public static void main(String[] args) {
        MyRunnableDemo demo = new MyRunnableDemo();
        Thread thread1 = new Thread(demo);
        Thread thread2 = new Thread(demo);
        Thread thread3 = new Thread(demo);
        thread1.start();
        thread2.start();
        thread3.start();
    }
}
public class MyRunnableDemo implements Runnable{
    int ticket;//不需要加static,因为只会创建一个MyRunnableDemo对象
    @Override
    public void run() {
        while (true){
            if (method()) break;
        }
    }
    //ctrl alt m--自动生成方法
    private  synchronized boolean method() {
        if (ticket<100){
            System.out.println(Thread.currentThread().getName()+"正在卖第"+ticket+"张票");
            ticket++;
        }else {
            return true;
        }
        return false;
    }
}

四、多线程中常用的成员方法

1、public final String getName() 
  • 获取线程的名字
2、public final synchronized void setName(String name)
  • final-不能被子类重写;
  • synchronized-代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行
  • 细节:
    • 如果没有给线程设置名字,线程也是有默认名字的。格式:Thread-X(X是序号,从0开始)
    • 如果需要给线程设置名字,可以通过setName方法,也可以通过构造方法
3、public static native Thread currentThread()
  • static:表示可以直接用类名调用,不需要实例化对象;通过native修饰的方法可以调用本地程序库或操作系统的API,以实现一些Java本身无法实现的功能
4、public static void sleep(long time)
  • 细节:哪条线程执行到这个方法,就会在此停留多长时间
5、public final int getPriority()
  • 获取线程优先级
6、public final void setPriority(int newPriority)
  • 设置线程优先级
  • 细节:
    • 线程的默认优先级是5
    • 最高优先级为10
    • 最低优先级为1
7、public final void setDaemon(boolean on)
  • 设置守护线程
  • 细节:
    • 当非守护线程执行完毕后,守护线程也会陆续结束,不会执行完

五、线程的生命周期

1、创建线程对象
2、就绪--抢CPU--有执行资格、没有执行权
3、运行--运行代码--有执行资格、有执行权
4、死亡--垃圾(运行完)
5、阻塞--等待--没有执行资格、没有执行权(sleep()或者其他阻塞方法)

posted @ 2023-04-13 23:24  小园初来乍到  阅读(23)  评论(0)    收藏  举报