多线程(3)

多线程练习

//两个客户到一个银行去存钱,每个客户一次存100,存3次。
//问题:该程序是否有安全问题,如果有,写出分析过程,并定义解决方案。

/*

发现运行结果:
sum=200
sum=300
sum=400
sum=200
sum=500
sum=600

打印错乱,不关心,但是发现数值错误,没有100.
运行了几次发现有对的。
sum=100
sum=300
sum=400
sum=200
sum=500
sum=600

说明多线程的随机性造成了安全问题发生。
哪的问题啊?
1,既然是多线程的问题,必须问题发生在线程任务内。
2,任务代码中是否有共性数据呢?有的,b对象的中的sum。
3,是否有对sum进行多次运算呢?有!

加同步就搞定。
*/

//描述银行。
class Bank
{
    private int sum;
    private Object obj = new Object();
    public void add(int num)
    {   
        synchronized(obj)
        {
            sum = sum + num;
            System.out.println("sum="+sum);//每存一次,看到银行金额变化。
        }
    }
}
class Consumer implements Runnable
{
    private Bank b = new Bank();
    public void run()
    {
        for(int x=0 ; x<3; x++)
        {
            b.add(100);//一次存100.循环3次,
        }
    }
}
class ThreadTest
{
    public static void main(String[] args)
    {
        Consumer c = new Consumer();
        Thread t1 = new Thread(c);
        Thread t2 = new Thread(c);
        t1.start();
        t2.start();

    }
}

static 同步函数,使用的锁不是this,而是字节码文件对象, 类名.class

class Ticket implements Runnable
{
    private static int tickets = 100;
    private Object obj = new Object();
    boolean flag = true;
    public void run()
    {
        if(flag){
            while(true){
                synchronized(Ticket.class){
                    if(tickets>0){
                        try{Thread.sleep(10);}catch(InterruptedException e){}
                        System.out.println(Thread.currentThread().getName()+"...obj..."+tickets--);//打印线程名称。
                    }
                }
            }
        }
        else{
            while(true){
                this.sale();
            }
        }
    }

    public static synchronized void sale()//
    {
        if(tickets>0)
        {
            try{Thread.sleep(10);}catch(InterruptedException e){}
            System.out.println(Thread.currentThread().getName()+"...sale..."+tickets--);//打印线程名称。
        }
    }
}
class ThreadDemo5 
{
    public static void main(String[] args) 
    {
        Ticket t = new Ticket();

        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);

        t1.start();
        try{Thread.sleep(10);}catch(InterruptedException e){}
        //切换标记,之前,让主线程停一会,这时就只有一个t1线程在,它就会执行同步代码块。
        t.flag = false;

        t2.start();
    }
}
//饿汉式。  多线程并发饿汉式没问题。
class Single
{
    private static final Single s = new Single();

    private Single(){}

    public static Single getInstance()
    {
        return s;
    }
}

//懒汉式。
class Single
{
    private static  Single s = null;

    private Single(){}

    /*
    并发访问会有安全隐患,所以加入同步机制解决安全问题。
    但是,同步的出现降低了效率。
    可以通过双重判断的方式,解决效率问题,减少判断锁的次数。

    */
    public static  Single getInstance()
    {
        if(s==null)
        {
            synchronized(Single.class)
            {
                if(s==null)
        //          -->0 -->1
                    s = new Single();
            }
        }
        return s;
    }
}



class Demo implements Runnable
{
    public void run()
    {
        Single.getInstance();
    }
}


class ThreadDemo6 
{
    public static void main(String[] args) 
    {
        System.out.println("Hello World!");
    }
}

同步的另一个弊端

情况之一:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。
这时容易引发一种现象:死锁
这种情况能避免就避免掉。

//Thread-0
synchronized(obj1)
{
    -->thread-0  obj1
    synchronized(obj2)
    {

    }

}
//Thread-1
synchronized(obj2)
{
    Thread-1 obj2
    synchronized(obj1)
    {

    }

}
class Ticket implements Runnable
{
    private  int tickets = 100;
    private Object obj = new Object();
    boolean flag = true;
    public void run()
    {
        if(flag){
            while(true){
                synchronized(obj){
                    sale();//this lock;
                }
            }
        }
        else{
            while(true){
                this.sale();
            }
        }
    }

    public  synchronized void sale()//this lock
    {
        synchronized(obj)//obj lock
        {
            if(tickets>0)
            {
                try{Thread.sleep(10);}catch(InterruptedException e){}
                System.out.println(Thread.currentThread().getName()+"...sale..."+tickets--);//打印线程名称。
            }
        }
    }
}
class ThreadDemo7 
{
    public static void main(String[] args) 
    {
        Ticket t = new Ticket();

        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);

        t1.start();
        try{Thread.sleep(10);}catch(InterruptedException e){}
        //切换标记,之前,让主线程停一会,这时就只有一个t1线程在,它就会执行同步代码块。
        t.flag = false;

        t2.start();
    }
}

死锁(DeadLock)的测试

class Test implements Runnable
{
    private boolean flag;
    Test(boolean flag)
    {
        this.flag = flag;
    }

    public void run()
    {
        if(flag)
        {
            while(true)
            {
                synchronized(MyLock.LOCKA)
                {
                    System.out.println(Thread.currentThread().getName()+"...if......locka");
                    synchronized(MyLock.LOCKB)
                    {
                        System.out.println(Thread.currentThread().getName()+"...if......lockb");
                    }
                }
            }
        }
        else
        {
            while(true)
            {
                synchronized(MyLock.LOCKB)
                {
                    System.out.println(Thread.currentThread().getName()+"...else......lockb");
                    synchronized(MyLock.LOCKA)
                    {
                        System.out.println(Thread.currentThread().getName()+"...else......locka");
                    }
                }
            }
        }
    }
}
//定义一个用于存储锁对象类。
class MyLock
{
    public static final Object LOCKA = new Object();
    public static final Object LOCKB = new Object();
}

class DeadLockTest 
{
    public static void main(String[] args) 
    {
        //创建两个线程任务。
        Test t1 = new Test(true);
        Test t2 = new Test(false);

        Thread t11 = new Thread(t1);
        Thread t22 = new Thread(t2);
        t11.start();
        t22.start();

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要求编写程序模拟银行账户的、取款操作。按要求完成以下步骤: 步骤1:编写程序Account.java,其中定义银行账户类Account。该类中有账号、姓名、 款余额等数据域,余额默认是0;有款、取款、获取当前余额等方法。其中账号为长度 为12位数字的字符串,姓名为字符串,款余额为double。 步骤2:编写名为CreditAccount类的信用卡账户类。该类继承自Account类,增加一 个透支限额(double)数据域,透支限额默认为1000。同时该类账户取款时允许透支,但不 能超过透支限额。 步骤3:编写名为SavingAccount的储蓄账户类SavingAccount。该类继承自Account 类。该类账户取款时不允许透支。 步骤4:编写名为Bank的模拟银行类,其中可以储多个类型可能是信用卡账户或储 蓄账户的对象(可以用数组或ArrayList实现)。该类包含以下方法: <1>开户:即增加一个新的账户,注意:不允许两个账户的账号相同 <2>销户:即删除一个已有的账户 <3>查询账户:根据一个账号,查询有无该账号的账户 <4>统计目前银行款总余额的方法。 <5>统计目前银行的信用卡账户总透支金额的方法。 <6>统计目前总账户数。 <7>统计目前信用卡账户数 <8>统计目前储蓄卡账户数 步骤5:编写客户端类Client.java完成以下功能: <1> 编写一个静态方法,创建一个银行对象,并随机生成10个账号从1000 0000 0000 0000到1000 0000 0000 0009,类型不同的账户。 <2> main方法中模拟几开户操作。 <3> main方法中模拟几销户操作。 <4> 模拟几个对指定账号的款和取款操作。 <5> 输出银行的总账户数、总余额、总透支数、各类具体账户数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值