java多线程的共享变量访问控制实例

来源:互联网 发布:深圳软件停车系统 编辑:程序博客网 时间:2024/06/07 14:27

最近打算去一家电商公司,对于高并发的数据访问控制有着严格的要求,近期打算把多线程的知识在好好补一下。
线程调度有五个状态;
开始,可运行,运行,阻塞,死亡。
启动线程有两种方法。继承Thread类或则实现Runnable接口,其实Thread类也实现了Runnbale接口并实现了接口中唯一的方法run。但是Thread实例只能启动一次,无法共享变量,因此Runnable的灵活性更高。Thread(Runnable target)可以去执行Runnable实例的run方法。虽然start方法和run方法执行的内容一样但是本质是不同的,run方法只是单纯的调用而已并没有启动多线程,而start方法可以启动多线程。去查看jdk源码可以发现start有本地native修饰符,这会调用系统函数,优化执行效率。
可运行是一个线程池,对于JVM一般是从线程池里选择优先级高的线程抢占式执行,如果优先级都一样,那就看谁运气好抢到CPU资源。一般可以自己设置优先级0~10。这里还有用户线程和守护线程,JVM实例会在用户线程结束时退出,而不会等待守护线程。
运行态即开始执行该实例的run方法。为了减缓执行可以采用线程Thread.sleep(休眠的毫秒数)去给其他线程执行机会,但sleep不会放弃对象的锁,要放弃锁可以调用超类的wait(放弃毫秒数)方法。notify和notifyAll也可以去唤醒。注意,醒来并不一定马上得到执行的机会,而是放在可运行池里,让JVM去调度到运行态。在运行的程序也可以通过yield方法让本线程放到可运行池里,因此不要依赖这个方法,这个方法可能并没什么用。只作为一个参考手段。为了等待该线程执行结束,可以使用jion方法。
死亡态:死亡后不能复生。

接下来我来实现一个共享变量的控制实例:
创建一个我的对象,它有成员变量money,用两个线程去执行它,给一个消费金额不断的去消费,一直消费到0。

主线程中的测试:

public static void main(String args[]) throws InterruptedException    {        MyObject myObject = new MyObject(10);        //定义两个线程来共享这个myObject        Thread t1 = new Thread(myObject,"Thread-----A");        Thread t2 = new Thread(myObject,"Thread-----B");        t1.start();        t2.start();        //这里要用join方法,否则主线程在t1,t2执行的过程中可能并行执行,然后返回最后剩下的money,我想要显示的最终的结果,因此使用join方法是使t1,t2结束。        t1.join();        t2.join();        System.out.println("============主线程休眠1秒");        try        {            Thread.sleep(1000);            Thread.yield();//将主线程放到线程池,这里不起作用。t1,t2已经死亡        }        catch(Exception e)        {            e.printStackTrace();        }        //判断最后的共享变量money的值        System.out.println("myObject当中Money最终为:"+myObject.money);    }

接下来我们来共享变量的对象,如果没用控制方法同步

class MyObject implements Runnable{    //可以对成员变量加锁//  volatile int money = 100;    int money = 10000;    //消费金额,用构造函数去初始化    private int consume;    //如果这里不加synchronized方法去控制    @Override    public void run() {        // TODO Auto-generated method stub        int i = 0;        while(money > 0)        {            System.out.println(Thread.currentThread().getName()+"执行操作"+ (i+1) +"次");            money = getSumMoney();            System.out.println("money:"+money);            i ++;        }        }        private int getSumMoney()    {        return this.money - consume;    }    //构造方法,消费    MyObject(int consume)    {        this.consume = consume;    }    public int getMoney() {        return money;    }}

运行结果:

//省略前面......Thread-----A执行操作810次money:100Thread-----A执行操作811次money:90Thread-----A执行操作812次money:80Thread-----A执行操作813次money:70Thread-----A执行操作814次money:60Thread-----A执行操作815次money:50Thread-----A执行操作816次money:40Thread-----A执行操作817次money:30Thread-----A执行操作818次money:20Thread-----A执行操作819次money:10Thread-----A执行操作820次money:0Thread-----B执行操作181次money:-10============主线程休眠1秒myObject当中Money最终为:-10

最终为-10,因为最后结果出现了问题。
我们加上访问修饰符synchronized

运行结果:

//....//..//.Thread-----A执行操作994次money:60Thread-----A执行操作995次money:50Thread-----A执行操作996次money:40Thread-----A执行操作997次money:30Thread-----A执行操作998次money:20Thread-----A执行操作999次money:10Thread-----A执行操作1000次money:0============主线程休眠1秒myObject当中Money最终为:0

结果算是没问题了,但是这里为什么只有A方法得到了执行呢?我再来分析代码,发现是线程A占用了对象的锁一直没释放,让线程B没有机会执行。为了达到两个线程都能够执行的目的,再加上wait方法放弃锁。代码如下:

public synchronized void run() {        // TODO Auto-generated method stub        int i = 0;        while(money > 0)        {            System.out.println(Thread.currentThread().getName()+"执行操作"+ (i+1) +"次");            money = getSumMoney();            System.out.println("money:"+money);            try            {                System.out.println(Thread.currentThread().getName() + "本线程放弃锁");                wait(50);            }            catch(Exception e)            {                e.printStackTrace();            }            i ++;        }        }

运行结果:

//..........Thread-----A本线程放弃锁Thread-----B执行操作496次money:90Thread-----B本线程放弃锁Thread-----A执行操作496次money:80Thread-----A本线程放弃锁Thread-----B执行操作497次money:70Thread-----B本线程放弃锁Thread-----A执行操作497次money:60Thread-----A本线程放弃锁Thread-----B执行操作498次money:50Thread-----B本线程放弃锁Thread-----A执行操作498次money:40Thread-----A本线程放弃锁Thread-----B执行操作499次money:30Thread-----B本线程放弃锁Thread-----A执行操作499次money:20Thread-----A本线程放弃锁Thread-----B执行操作500次money:10Thread-----B本线程放弃锁Thread-----A执行操作500次money:0Thread-----A本线程放弃锁============主线程休眠1秒myObject当中Money最终为:0

很好,问题得到了解决,交替执行并保证了数据的正确性。

0 0
原创粉丝点击