多线程常用操作及线程锁

多线程有很多的方法定义,大部分都在Thread类里面,我们这里强调几个与我们日常开发有关的方法。
复制代码

线程的命名与取得

先来看下Thread类的构造函数

这里由两个可以在创建线程时指定名字的构造函数。

然后在Thread类中也有设置和取得名字的函数。如下:

因为这些方法是在Thread类里面的,如果换回Runnable接口实现的线程,它的定义里面并没有这些方法。

所以想取得线程的名字,也只是能取得当前执行run()方法的线程名字。(在一个时间点上,只能有一个线程操作)

在Thread类中就有这么一个方法:取得当前线程的名字

常用操作就为: Thread.currentThread().getName() ----> 取得当前线程名字

线程的休眠

所谓线程的休眠就是指让当前执行的线程进入到一个阻塞状态。

这个方法很见名知意呀,让当前线程睡一会。

但是这个方法会抛出一个异常。

这是一个中断异常。就相当于你在睡觉,突然有人把你吵醒一样,那你起床气不来了么。哈哈。

注意点:如果在多线程操作时,所有线程都会休眠。

线程优先级

我们知道线程的执行顺序是由CPU进行调度的,分配了时间片就可以执行,但是如果我们想让线程有先后顺序呢?

  • 设置优先级: public final void setPriority(int newPriority)
  • 取得优先级: public final int getPriority()

我们看到设置和取得都是整型变量,这是个什么意思呢?

我们可以在Thread类中看到有这么3个常量,通过注释,我们知道可以用它们来设置线程的优先级。

注意:设置线程的优先级是处于理论上的,并不能完全保证线程的优先级越高就一定会先执行这个线程

线程的同步与死锁

线程的同步就是多个线程访问同一资源时需要考虑的问题。

比如:

    我卖20张票,应该是票卖完了就不能卖了。所以我会判断当票大于等于1时,我才能卖票,然后对票数递减。
但是在最后一张票时,一个线程(人买票)进来,发现有一张票,好,可以过了判断。但是刚好过了判断,没有对票数递减时,这个线程的执行时间结束了!
然后另外一个线程获取到时间片进来了,它也进行判断,发现 诶,还有一张票,过了判断然后对票数递减,这时已经没有票了。
那么上一个过了判断的线程再次获取到时间片,但是它是已经过了判断的,所以它也对票数递减。这样票数就成负数了。这是错误的。所以我们在处理多线程时,一定要着重注意此类问题。
复制代码

同步处理

我们观察上面举的案例,发现判断和递减是分步操作所以才会有别的线程钻了空子,从而引发安全问题。

所以我们应该把判断和递减弄成一步操作(可以说是事务),那么问题不就解决了么。

Java中有一个关键字:synchronized 这算是Java中单词最长的关键字了,哈哈。

第一种:public synchronized void test(){}

第二种: synchronized(锁对象){ 代码块 }

它可以在方法上使用,表明是个同步方法。也可以只针对某一代码块使用。

多线程运行时,有且只有一个线程能对这个方法进行操作(进入时会把这个方法给锁上)。别的线程要想进入必须等上一个线程把这个方法执行完(执行完时会把锁给释放)。

这个关键字就可以帮我们解决以上的问题啦。

注意点:这个锁对象一定要是多线程共同对应的对象,要不然一个线程拿着A锁,一个线程拿着B锁,毛用没有呀。一般情况下我们都是使用当前类对象:this

死锁

通过以上解释可以分析出,所谓的同步就是一个线程等待另一个线程执行完才可以执行,但是同步过多就有可能导致一个很严重的问题:死锁

死锁通俗点解释就是:

线程A进入同步方法A,拿到A锁,线程B进入同步方法B,拿到B锁。但是方法A中需要调用方法B,方法B也需要调用方法A。
我们知道加了同步后,线程必须得一个一个执行。
上面的情况就是:A没执行完(拿着A锁,没有释放),需要调用B。B没执行完(拿着B锁,没有释放),需要调用A。

但是这样能调用吗?是不是A和B就在互相较劲了。你不能调用我,我也不能调用你,就卡死在这了。这就是我们说的死锁。
复制代码

通常情况死锁并不会频繁产生,只需要开发人员在编码时注意点就行。

最后来个多线程中最具有代表性的生产者和消费者模型。

package com.wuzzzh.thread;

class Info {

    private String name;
    private String job;
//    private boolean flag = true;

// 第一版去除 synchronized
    public synchronized void set(String name, String job)  {
//        if(flag == false){
//            try {
//                this.wait();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
        this.name = name;
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.job = job;

//        flag = false;
//        this.notify();
    }
    
// 第一版去除 synchronized
    public synchronized void get() {
//        if(flag == true){
//            try {
//                this.wait();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("name= " + name +
                ", job= " + job);

//        flag = true;
//        this.notify();
    }


}

class Productor implements Runnable {

    private Info info;

    public Productor(Info info) {
        this.info = info;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {

            if (i % 2 == 0) {
                info.set("cuz", "小奶狗");
            } else {
                info.set("wes", "大狼狗");
            }
        }
    }
}

class Custormer implements Runnable {

    private Info info;

    public Custormer(Info info) {
        this.info = info;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            info.get();
        }
    }
}


/**
 * @Description: // TODO 多线程生产者与消费者模型
 * @Author: Wuzzzh
 * @Create: 2019/5/4
 */
public class ThreadDemo {

    public static void main(String[] args) {
        Info info = new Info();
        new Thread(new Productor(info)).start();
        new Thread(new Custormer(info)).start();
    }
}

复制代码

这其中分为三个版本:

第一个版本:注释中的什么都不放开,并把方法上的synchronized关键字去除。

第二个版本:给方法上加上synchronized关键字。

第三个版本:方法上加上synchronized关键字并把注释全部解开。

第一个版本运行后有以下问题:

  • 输出的文字有很多重复
  • 输出的文字错乱

第二个版本运行后:

  • 解决了文字错乱问题
  • 但是文字重复问题更加严重

第三个版本运行后:

  • 这才是我们想要的结果嘛。(生产一个消费一个)

转载于:https://juejin.im/post/5ccd55d5f265da034d2a2547

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值