JAVA 多线程开发

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40990836/article/details/79039130

一、 多线程开发

进程 : 系统进行资源分配的基本单位
线程 : 是系统独立跳读和分配CPU的基本单位指令运行时的程序的调度单位
注意 : 进程内有一个相对独立的,可调度的执行单元
多线程 : 计算机内因有硬件支持,而能够在同一时间执行多与一个线程的开发技术

二、 线程和进程的关系

  1. 进程是线程的容器, 一个进程至少包含一个线程,包含多个线程的进程称之为多线程开发.
  2. 线程是进程中一个独立,可调度的执行单位,运行资源的内存有所属进程分配.

三、如何实现多线程

  1. 继承Thread类
    i . 创建子类
    ii . 生成子类对象
    iii . 子类对象开启线程
  2. 实现 Runnable 接口
    i . 创建实现类,实现run 方法
    ii . 生成实现类对象
    iii . 为实现类对象分配线程并开启
//  ① 继承Thread 类
public class Child extends Thread{
    //  问题: 
    private String name;
    public String getSelfName(){
        return name;
    }
    public void setSelfName(String name){
        this.name = name;
    }
    public child(){
        super();
    }
    public Child(String name,String tName){
        super(tName);    //  tName  线程名
        this.name = name;
    }
    //  重写run方法
    public void run(){
        //  完成自身多线程功能
        bowl();
        //  功能后 线程任务上交父级
        super.run();
    }
    public void bowl(){
        for(int i = 0; i < 3; i++){
            System.out.println("2018" + name + "梦想成真")
        }
    }
}
//  测试类
public class Test{
    public static void main(String[] args){
        //  创建实现类的对象
        Child c1 = new Child("小明","明明进程");
        Child c1 = new Child("小明","明明进程");
        Child c1 = new Child("小明","明明进程");
        System.out.println(c1.getName);   //  打印明明进程
        System.out.println(c1.getSelef);  //  打印小明姓名
        //  获取当前所在线程名 ==   Thread.currentThread().getName();
        //  实现类对象开辟线程
        c1.start();
        c2.start();
        c3.start();
    }
}

问题 : 实现类拥有 name 属性时,标准的get set 方法会报错
原因 : Thread 类 也拥有同名的name 属性(用于记录当前线程名),错误原因出在name 属性的 get set 方法,也是标准写法,但是被final 所修饰,所以实现类的标准 get set 方法 出现了强行重写final修饰的方法的错误
解决 : 将实现类 get set 方法定义为非标准化的
规避 : 实现类不建议拥有 name 属性

  1. 实现 Runnable 接口 实现多线程

原因: 当资源(java类)作为多个线程共有的资源
结论: 将此类情况的java类定义为Runnable接口的实现类以供多个线程共同持有

   //  ① 实现 runnable 接口
public class Ticket implements Runnable{
    private int num;
    //  get  set 方法
    public int getNum(){
        return num;
    }
    public void setNum(int num){
        this.num = num; 
    }
    //  构造方法, 初始化 num 值 ,  票数总数为 20
    public Ticket(){
        this.num = 20;
    }
    //  实现run 方法
    @Override
    public void run(){
        //  调用卖票的方法
    }
    //  卖票 
    //  添加同步锁  
    //  ① synchronized 作为方法的关键词
    //  i) 该方法为同步方法
    //  目的: 同一时刻只能被一个线程锁调用
    //  该方法为同步方法: 同一时刻只能被一个线程锁调用
    //  应用场景:  方法功能单一,且方法需要整体做同步处理
    //  ② synchronized 作为同步代码块
    //  i) 代码块为同步代码块
    //  目的: 代码块同一时刻,只能被一个线程锁使用
    //  应用场景 : 方法功能逻辑较多,方法需局部做同步处理
    public static final Object mutex = new Object();
    private void sellTicketSuper(){
        //  静态代码块 synchronized
        //  参数: mutex 任意的唯一对象
        //  通常: 互斥锁标识
        //  static 方法中: Ticket.class (当前类)
        //  成员方法中:  this
        //  this 不唯一时:  static final Object
        while(true){
            //  卖票的窗口号:  线程名 Thread.currentThread().getName()
            String name = Thread.currentThread().getName();
            //  一票一锁: 抢到票,可以卖票,买了抢到那张票之后,才会开锁
            synchronized(mutex){ // 加锁的开始
                if(num > 0){
                    //  窗口所卖的票次
                    int temp = 20 - num + 1;
                    System.out.println(ctName + "抢到第" + temp + "张");
                    //  卖出一张, 票数减少1, 结果为剩余票数
                    num--;
                    System.out.println("剩余票数" + num);
                }
            } // 开锁的标识
            //  结束卖票判断
            if(num <=0){
                break;
            }
            //  锁住的逻辑较多时,可能执行过程中多次让出CPU执行权.导致其他线程
            //  在未开锁状状态区竞争资源,从而进入了锁池状态,失去下一次CPU第一时刻经证权
            //  所有需要开锁的线程在开锁后 < 强行让出CPU执行权 >
            Thread.yield();
        }
    }
}
// 测试类测试
public class Test{
    public static void main(String[] args){
        //  实例化一个对象
        Ticket01 t1 = new Ticket01();
        //  创建一个线程
        Thread th1 = new Thread(t1,"一号窗口");
        Thread th2 = new Thread(t1,"二号窗口");
        Thread th3 = new Thread(t1,"三号窗口");
        th1.start();
        th2.start();
        th3.start();
    }
}

volatile

volatile 在多个线程访问一个资源时, 多个线程中的任意一个线程修改了资源值,会将资源修改信号和修改值马上同步给其他所有访问路线
内外都需要访问 – 定义public static
多个线程需要访问 – volatile

猜你喜欢

转载自blog.csdn.net/qq_40990836/article/details/79039130