多线程解决现实中的抢票问题
以下为两种解决方式:
1.实现Runnable接口
2.继承自Thread
1.第一种方法(正确)
Public class A extends Thread{ Public static int tickets = 100; Public static String str = new String(“哈哈”); Public void run(){ While(true){ Synchronized( str ){ If (tickets > 0 ){ System.out.println(“第%s个线程卖出了第%d张票, Thread.currentThread().getName(),tickets”); --tickets; } } } } } Public class Main { Public static void main ( String [ ] args ){ A aa1 = new A (); aa1.start(); A aa2 = new A(); aa2.start(); } }
解释:两个线程两个对象aa1 和 aa2 ,两个.start()方法,开启了两个run()方法,所以如果想让它卖一种票就对tickets进行静态处理,如果还想让两个线程互斥,则要统一str,因为是两个对象锁定各自的str,要对其进行静态处理,因为Synchronized( str ){ }该方法。
2.用第二种方法来实现卖票(正确)
Public class A implesant Runnable{ Publc int tickets = 100; string str = new String(“哈哈”); Void run (){ While(t){ Synchroniched(str){ If(tickets > 0 ){ System.out.println(“第%s个线程卖掉了第%d张票”); -- tickets; } } } } } Public class Main { Public static void main(String [] args){ A aa = new A(); Thread tt1 = new Thread(aa); tt.start(); Thread tt2 = new Thread(aa); tt.strat(); } }
解释:
第二种方法为什么不需要static 而第一种方法需要
A aa = new A();
Thread t = new Thread(aa);
用一个aa对象可以同时构建多个线程,一个对象就默认共享同一个资源,所以就是卖同一张票。
所以相比较而言,最好用第二种方法,创建一个对象就可以同时构建多个线程,并且还共享同一个资源,也节省对象资源。
3.错误示范1
Public class A implesant Runnable{ Publc int tickets = 100; string str = new String(“哈哈”); Void run (){ While(true){ { Synchroniched(str){ If(tickets > 0 ){ System.out.println(“第%s个线程卖掉了第%d张票”); -- tickets; } } } } Public class Main { Public static void main(String [] args){ A aa = new A(); Thread tt1 = new Thread(aa); tt.start(); Thread tt2 = new Thread(aa); tt.strat(); } }
那么我们试想以下可不可以这样写呢?
这样写会导致什么情况呢?
答:会导致只有一个线程在运行,run方法直接被其中一个线程霸占后另一个不能调用run方法,不让别的线程卖票了。
所以这种写法是错误的,不合理的。
4.错误示范2
Public class A implesant Runnable{ Publc int tickets = 100; Void run (){ string str = new String(“哈哈”); While(true){ { Synchroniched(str){ If(tickets > 0 ){ System.out.println(“第%s个线程卖掉了第%d张票”); -- tickets; } } } } Public class Main { Public static void main(String [] args){ A aa = new A(); Thread tt1 = new Thread(aa); tt.start(); Thread tt2 = new Thread(aa); tt.strat(); } }
这种写法也是不对的,因为string str = new String(“哈哈”); 在run()方法里面,虽然Thread tt1 = new Thread(aa);和Thread tt2 = new Thread(aa);都调用同一个类对象,但是run方法分别被调用一次,所以str为两种,所以就是各卖各的票,没有互斥。所以这种写法依然不合理。
5.错误示范3
Public class A implesant Runnable{ Publc int tickets = 100; string str = new String(“哈哈”); Void run (){ string str = new String(“哈哈”); //可以定义一个局部变量,局部变量和属性名字相同 While(true){ { If(tickets > 0 ){ System.out.println(“第%s个线程卖掉了第%d张票”); -- tickets; } } } } Public class Main { Public static void main(String [] args){ A aa = new A(); Thread tt1 = new Thread(aa); tt.start(); Thread tt2 = new Thread(aa); tt.strat(); } }
在方法内部定义一个局部变量,局部变量是可以和属性名字相同的,那么就意味着run()方法中str是局部变量的str,所以依然各卖各的票,没有互斥。所以这种写法依然不合理。
证明:
Class A{
Int i = 10 ;
Public void f(){
Int i = 20;
System.out.println(“i = ” + i );
}
}
Public class Main{ Public static void main(String [] args){ New A().f(); } }
运行结果为20,以此证明run()方法中str是局部变量的str.
注意看,这种方式呢?
Public class A implesant Runnable{ Publc int tickets = 100; Public void run (){ String str = “哈哈”; While(true){ { Synchroniched(str){ If(tickets > 0 ){ System.out.println(“第%s个线程卖掉了第%d张票”); -- tickets; } } } } Public class Main { Public static void main(String [] args){ A aa = new A(); Thread tt1 = new Thread(aa); tt.start(); Thread tt2 = new Thread(aa); tt.strat(); } }
答:这种写法是正确的
解释:
因为String str = new String(“哈哈”);是把数据放在堆区,
而String str = “哈哈”;是把数据放在数据区,数据区如果数值相同就是指向同一个对象。
所以即使String str = “哈哈”在run函数里面,但是两个线程指向的同一个str,就能够互斥。
因此写法正确。