多线程的创建与同步

下面咱们来了解下什么是多线程?

思考 : 能否在同一个Java应用程序中执行2个以上的无限循环呢?

1.1什么是多线程?

是指一个应用程序中有多个线程并发执行。

1.2并发:

通过CPU的调度算法,使用户感觉像是同时处理多个任务,但同一时刻只有一个执行流占用CPU执行。即使多核多CPU环境还是会使用并发,以提高处理效率。(切换执行)

多线程技术并不能直接提高程序的运行效率,而是通过提高CPU的使用率的方式来达到提高效率的目的。

1.3 问题 : 线程是不是越多越好呢?

线程并不是越多越好。 对于一个CPU而言,同一时刻,只能执行一个任务。同一时间段内,如果线程过多,每个线程被切到的时间就变少了。因此,
线程并不是越多越好。 (例如: 迅雷下载, 喂宝宝吃东西)

然而,咱们经常写的main方法就是一个线程(主线程)

2.1线程应该怎么创建呢?

线程的创建有两种;
方式一:继承Thread类

2.1.2 实现步骤及演示

1.自定义一个类,继承Thread类。
2.重写run()方法
3.创建线程类的对象
4.启动线程

2.1.3 代码实现:

package cn.itcast.multithread01;

public class Demo03 {
    public static void main(String[] args) {

        // 1. 创建一个 Test03 类的对象
        Test03 t1 = new Test03("one");
        t1.start();

        // 2. 在创建一个 Test03 类的对象
        Test03 t2 = new Test03("two");
        t2.start();

        // 3. main 线程的代码
        while (true) {          
            System.out.println("main run ...");
        }
    }
   }

// 创建线程实现方式一 : 继承 Thread 类
class Test03 extends Thread {
    // 属性
    private String name;

    public Test03(String name) {
        this.name = name;
    }

    // 行为
    @Override
    public void run() {
        while (true) {          
            System.out.println(name + " run ...");
        }
    }
}

面试题:start 方法和run方法的区别?

run:仅是对象调方法,不调用系统资源开辟新线程
start:调用系统资源,开辟新线程

获取线程的名称:

Thread 类的子类 : 子类对象.getName();
非线程类 :Thread.currentThread().getName(); (重要)

方式二:实现runnable接口

2.2.1 实现步骤及演示:

1.自定义一个类,实现runnable接口。
2.重写run方法
3.创建线程任务类对象
4.创建线程对象,将任务类对象作为参数传入
5.启动线程

2.2.2 代码实现:

public class test implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());

    }

    public static void main(String[] args) {
        test task = new test();
        Thread t1 = new Thread(task,"线程一");
        Thread t2 = new Thread(task,"线程二");
        t1.start();
        t2.start();
    }
}

实现原理:
2.2.3 为什么给thread传入runnable接口参数,就会执行run方法?

当我们创建线程对象时,我们已经将task任务类对象传递给线程对象,其作用是把task赋值给内部属性target进行储存,当我们调用Thread的start方法时,会判断target是否为null,因此target不为null,就会执行run方法。

以下是Thread源码
这里写图片描述

2.2.4 .两种实现多线程方式的对比分析

    方式一:继承Thread方式
      1. 优点: 可以在子类中增加新的成员变量, 使线程具有某种属性, 也可以在子类中增加新的方法, 使线程具有某种功能. 
      2. 缺点:由于Java不支持类的多继承, Thread 类的子类不能在扩展其他的类
方式二: 实现Runnable接口       
  1. 避免了Java单继承带来的局限性
  2. 适合多个相同程序代码的线程去处理同一个资源的情况, 更灵活的实现数据的共享。

3. 线程同步问题

  1. 需求假设某航空公司有三个窗口发售某日某次航班的100张票.这时,100张票可以作为共享资源,三个售票窗口需要创建三个线程. 使用代码模拟实现.(一共100张!)

    1. 线程并发产生的问题和原因分析
      1. 现象:多个线程在操作共享的数据,并且对共享数据有修改会产生错乱的现象
      2. 原因:CPU在处理多个线程的时候,在操作共享数据的多条代码之间进行切换导致的
    2. 解决方案

      1. 同步代码块

        1. 作用 : 被同步代码块包裹的代码在任何时刻只能被一条线程访问.
        2. 语法 :
          synchronized (锁对象) {
          被包裹的代码…
          }
        3. 锁对象
          1. 锁对象可以是任意类型的对象.
          2. 必须要包装锁对象的 唯一性.
            1. 注意点 : 锁对象千万不能定义在 run() 方法中, 原因是 run() 方法是被多条线程同时执行的, 因此就会创建出多个 锁对象.
            2. 锁对象要定义为成员属性
          3. 问题 : this 能保证数据安全吗?
            1. 可以的,只要保证当前类只有一个实例
        4. 注意
          1. 线程同步可以避免并发问题,但是同时也降低了执行效率
          2. 一般在修改共享资源的代码上同步(有可能并发修改的代码)
      2. 同步方法

        1. 语法:在方法上添加关键字synchronized
          1. 修饰符 synchronized 返回值类型 方法名(参数列表) {方法体...}
        2. 同步方法有锁对象,锁对象是this
        3. 静态同步方法中的锁对象是 类名.class

生命周期

这里写图片描述

以上写的不对的地方,请及时通知博主,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值