关于Java资源共享的问题

有地方说,Java不同线程资源共享要通过实现Runnable接口,而通过继承Thread不能实现资源共享。 其实这里有一个误区: 我们以猴子抢香蕉为例

public class Monkey extends Thread{
    //为了更直观看到结果,使用公平锁
    public Lock lock = new ReentrantLock(true);
    public Integer banana = 10;
    @Override
    public void run() {
        for(;;) {
            lock.lock();
            if(banana<=0){
                System.out.println("香蕉抢完了");
                break;
            }
            System.out.println(super.getName() + "抢到了香蕉:" + banana--);
            lock.unlock();
        }
    }
}
class Main{
    public static void main(String[] args) {
        Thread thread1 = new Monkey();
        Thread thread2 = new Monkey();
        thread1.start();
        thread2.start();
    }
​
}

定义了两个猴子线程,让这两个猴子去抢香蕉,大致一看没什么问题,但实际运行结果却是这样。

看到这估计大家已经知道问题所在了。这分明是两个线程自己执行自己的。相当于我们本来想要的效果是在一个世界里有两个猴子抢十个香蕉,但是现在却成了两个猴子分别在自己的世界里拿自己的香蕉。

实际上误区就在这里,我们new了两个线程,虽然这两个线程是同一个类,但实际上是创建了两个猴子对象,这两个对象各自执行自己的run方法。我们通过源码分析。

Runnable接口里只有一个run()方法,该方法代表线程体,也就是用户线程的核心代码。

Thread类的构造器可以添加参数Runnable类型的变量。
Thread类有一个Runnable类型的target变量。

在Thread的init()方法中,会将传入的Runnable类型的变量传给target变量。

然后再Thread的run()方法中,会判断target变量是否为空(也就是是否传入Runnable类型的变量),如果不为空,就执行target的run()方法,也就是传入的Runnable类型的对象的run方法。

所以,我们要实现的是让多个线程执行同一个run()方法,而不是自己执行自己的run()方法。 就可以通过Thread的构造器将Monkey对象传入,这样Monkey对象只有一个,run方法也就只有一个,多个线程执行的也是同一个run()方法。

修改后代码:

public class Monkey extends Thread{
    public Lock lock = new ReentrantLock(true);
    public Integer banana = 10;
    @Override
    public void run() {
        for(;;) {
            lock.lock();
            if(banana<=0){
                System.out.println("香蕉抢完了");
                break;
            }
            System.out.println(Thread.currentThread().getName() + "抢到了香蕉:" + banana--);
            lock.unlock();
        }
    }
}
class Main{
    public static void main(String[] args) {
        Monkey monkey = new Monkey();
        //Thread类也是实现了Runnable接口
        Thread thread1 = new Thread(monkey);
        Thread thread2 = new Thread(monkey);
        thread1.start();
        thread2.start();
    }

}

执行结果:

总结:

继承Thread类并不是不能实现资源共享,资源共享在于多个线程执行同一个核心代码块(不绝对),因此要通过Thread构造器传入Runnable类型的参数,让多个参数执行这个Runnable的run()方法。

延申:
还可以通过这种形式

public class Monkey extends Thread{
    Banana b;
    Lock lock;
    public Monkey(Banana b,Lock lock){
        this.b = b;
        this.lock = lock;
    }
    @Override
    public void run() {
        for(;;) {
            lock.lock();
            if(b.banana<=0){
                System.out.println("香蕉抢完了");
                break;
            }
            System.out.println(Thread.currentThread().getName() + "抢到了香蕉:" + b.banana--);
            lock.unlock();
        }
    }
}
class Banana{
    Integer banana = 10;
}
class Main{
    public static void main(String[] args) {
        Banana banana = new Banana();
        Lock lock = new ReentrantLock(true);
        Thread thread1 = new Monkey(banana,lock);
        Thread thread2 = new Monkey(banana,lock);
        thread1.start();
        thread2.start();
    }

}

即将共享资源提出来,作为唯一对象传给两个线程。尽管两个线程执行了两个run()方法,但是在各自的run()方法中,操作的资源(变量)是同一个。

运行结果:

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值