多线程练习
//两个客户到一个银行去存钱,每个客户一次存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();
}
}