多线程总结(上)

目录

一、进程和线程概念

1.1 进程

1.2 线程

1.3 例子

二、线程

2.1 Java中如何实现多线程

2.1.1 继承Thread类并重写run方法

  2.1.2 实现Runnable接口

2.2 Thread类中常用的方法

2.1.1 休眠

 2.2.2 放弃

 2.2.3 加入

 2.2.4 优先级

 2.2.5 线程守护

 三、多线程安全问题

3.1 多线程安全问题演示:

3.2 在程序应用中,如何保证线程的安全性


一、进程和线程概念

1.1 进程

①进程是正在运行的程序

②它是操作系统分配资源的基本单位

1.2 线程

线程,又成轻量级进程(Light Weight Process),是进程中的一条执行路径,也是CPU的基本调度单位。一个进程由一个或多个线程组成,彼此间完成不同的工作,同时执行,成为多线程。

1.3 例子

①迅雷---是一个进程,当中的多个下载任务即为线程

②JVM---Java虚拟机是一个进程,当中默认包含主线程(main),可通过代码创建多个独立线程,与main并发执行。

二、线程

2.1 Java中如何实现多线程

第一种:继承Thread类并重写run方法

第二种:实现Runnable接口

第三种:实现Callable接口

2.1.1 继承Thread类并重写run方法

 ① 获取当前线程的名称

第一种:通过父类Thread中的getName()可以获取线程名称。必须为Thread的子类

第二种: 通过Thread类中的静态方法currentThread获取当前线程,getName()获取线程名。任意处获取线程名。

 ②为线程起名

通过setName()为线程起名

 

  2.1.2 实现Runnable接口

 记住:能实现接口的就不要继承父类。因为父类只需要单继承。拓展性比较差

例子:

 

 多个窗口公卖同一张票,而且也会出现超卖的现象。----多线程操作公共数据时出现的线程安全问题。

2.2 Thread类中常用的方法

2.1.1 休眠

public static void sleep(long millis)

当前线程主动休眠millis毫秒

 2.2.2 放弃

public static void yield()

当前线程主动放弃时间片,回到就绪状态,竞争下一次时间片

A和B交替的概率高 

 2.2.3 加入

public final void join()

允许其他线程加入到当前线程中,直到其他线程执行完毕后,当前线程才会执行

 2.2.4 优先级

线程对象.setPriority()

线程优先级1-10,默认为5,优先级越高,表示获取CPU的概率越高

 2.2.5 线程守护

线程对象.setDaemon(true);设置为守护线程
  • 线程有两类:用户线程(前台线程)和守护线程(后台线程)
  • 如果程序中所有前台线程都执行完毕了,后台线程也会自动结束。      
  • 垃圾回收线程属于守护线程。

 三、多线程安全问题

  • 当多线程并发访问临界资源时,如果破坏原子操作,可难会造成数据不一致
  • 临界资源:共享资源(同一对象),一次仅允许一个线程使用,才可保证其正确性
  • 原子操作:不可分割的多步操作,被视作一个整体,其顺序和步骤不可打乱或缺省

3.1 多线程安全问题演示:

 需求: A线程将“Hello”存入数组;B数据将“World”存入数组。


public class Test05 {
//创建数组
private static String arr[]=new String[2];
//下标
private static int index=0;
 
public static void main(String[] args) throws InterruptedException {
//需求: A线程将“Hello”存入数组;B数据将“World”存入数组。
    Thread t1 = new Thread(new Runnable() { //匿名内部类
        @Override
        public void run() {
            if (arr[index]==null){
                arr[index]="hello";
                index++;
            }
        }
    });
    Thread t2 = new Thread(new Runnable() { //匿名内部类
        @Override
        public void run() {
            if (arr[index]==null){
                arr[index]="world";
                index++;
            }
        }
    });
    //开启线程
    t1.start();
    t2.start();
 
    t1.join();
    t2.join();
    //t1和t2执行完毕才执行下方的打印
    System.out.println(Arrays.asList(arr));
    }
}

3.2 在程序应用中,如何保证线程的安全性

3.2.1 同步方式

同步代码块:synchronized(临界资源对象){   //对临界资源对象加锁

                       //代码(原子操作)

                      }

注意:

  •          每个对象都有一个互斥锁标记,用来分配给线程的
  •          只有拥有对象互斥锁标记的线程,才能进入对该对象加锁的同步代码块
  •          线程退出同步代码块,会释放相应的互斥锁标记

修改上方演示代码 :加入synchronized

public class Test05 {
//创建数组
private static String arr[]=new String[2];
//下标
private static int index=0;
 
public static void main(String[] args) throws InterruptedException {
//需求: A线程将“Hello”存入数组;B数据将“World”存入数组。
    Thread t1 = new Thread(new Runnable() { //匿名内部类
        @Override
        public void run() {
            //synchronized 同步(互斥锁)
            synchronized (arr){ //同步代码块 必须获取()锁资源才能进入同步代码块中
                 //这里的操作必须原子操作要求
                if (arr[index]==null){
                    arr[index]="hello";
                    index++;
                }
            }
        }
    });
    Thread t2 = new Thread(new Runnable() { //匿名内部类
        @Override
        public void run() {
            synchronized (arr){
                if (arr[index]==null){
                    arr[index]="world";
                    index++;
                }
            }
        }
    });
    //开启线程
    t1.start();
    t2.start();
 
    t1.join();
    t2.join();
    //t1和t2执行完毕才执行下方的打印
    System.out.println(Arrays.asList(arr));
 
    }
}

解决案例2的线程安全问题  (this)临界资源对象

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值