Java多线程基础(二)

一、数据共享

使用Thread对同一个可运行对象r创建了三个线程,三个线程共享了一个数据

package com.runbable;

//操作同一对象实现数据共享
//以银行取钱为例
public class Thread002 implements Runnable{
    //定义私有变量
    private int money=10000;
    //定义取款金额
    int n;
    Thread002(int n){
        this.n=n;
        System.out.println("取款金额为"+this.n+"元");
    }
    public void run(){
       while(true) {
            if(money>0) {
                money -= n;
                System.out.println(Thread.currentThread().getName()+"取款后"+"剩余" + money + "元");
            }else{
                System.exit(0);
            }
        }
    }
}
class Thread002test{
    public static void main(String[] args) {
        //创建一个对象
        Thread002 r=new Thread002(1000);

        //将对象由Thread创建三个线程
        Thread t1=new Thread(r,"丈夫");
        Thread t2=new Thread(r,"妻子");
        Thread t3=new Thread(r,"父亲");
        //开始执行线程
        t1.start();
        t2.start();
        t3.start();

        try{
            Thread.sleep(1000);
        }catch(InterruptedException e){
            System.out.println("线程休眠失败");
        }
        System.out.println("主线程结束");
    }
}

结果:
取款金额为1000元
妻子取款后剩余8000元
丈夫取款后剩余8000元
父亲取款后剩余7000元
妻子取款后剩余6000元
父亲取款后剩余4000元
丈夫取款后剩余5000元
父亲取款后剩余2000元
妻子取款后剩余3000元
父亲取款后剩余0元
丈夫取款后剩余1000元

以上结果怎么看都别扭,这是因为数据虽然共享了,但顺序还是很奇怪,几个线程自己干自己的,没有交流,不安全,下面的线程同步可以解决此问题
以上代码测试类中主线程里面的sleep()方法并没有执行,甚至主线程都没有执行完全就被强制结束了,这是因为在封装类中使用了System.exit(0),当money小于0时,所有线程被强制结束,主线程没有执行完全就结束

二、线程同步

以上我们知道数据共享是存在很多问题的,很不合逻辑,或者说不安全,这是因为一个线程在运行时,另一个线程可能也在运行,交叉操作,当一个线程操作完数据后,数据还没有更新,另一个线程也开始操作,导致逻辑混乱。
为解决这种问题,我们希望在对共享数据进行操作时,这个操作应该是“原子操作”,即在当前线程操作时,不允许其他线程进入,这样每次得到的数据都是同步的,这就是线程同步

Java提供了“锁”机制对线程同步进行支持,如synchronized锁

一、同步代码块
synchronized(同步对象){
需要同步的代码块;
}

一、同步代码块
这里使用需要一个对象锁

二、同步方法
synchronized void fun(){

}

同步代码块

//实例化一个对象作为锁
Object mylock=new Object();
        synchronized ("mylock"){
        }

同步方法

public synchronized void run() {
        }

结果

取款金额为1000元
丈夫取款后剩余9000元
妻子取款后剩余8000元
妻子取款后剩余7000元
妻子取款后剩余6000元
妻子取款后剩余5000元
妻子取款后剩余4000元
妻子取款后剩余3000元
妻子取款后剩余2000元
妻子取款后剩余1000元
妻子取款后剩余0元

此时线程同步,符合逻辑

三、线程通信

由于线程A和线程B持有同一个类的对象object,尽管这两个线程需要调用不同的方法,但是它们是同步执行的
比如:线程B需要等待线程A执行完了methodA()方法之后,它才能执行methodB()方法。这样,线程A和线程B就实现了 通信。

wait()、notify()和notifyAll()

方法wait()使当前执行代码的线程进行等待,在调用wait()之前,线程必须获得该对象的对象级别锁,即只能在同步方法或同步块中调用wait()方法。在执行wait()方法后,当前线程释放锁。

方法notify():也要在同步方法或同步块中调用,即在调用前,线程也必须获得该对象的对象级别锁。唤醒等待的第一个线程
  方法notufyAll():唤醒等待的所有线程,按优先级执行
  总结:wait使线程停止运行,而notify使停止的线程继续运行

猜你喜欢

转载自blog.csdn.net/weixin_43688691/article/details/89061445
今日推荐