Java多线程(2)——多线程安全(传智播客毕老师视频讲解)

时间:2022-04-22 17:31:26

有如下代码

public class RunnableDemo2 implements Runnable
{
int i=10;
public void run()
{
for(;i>0;i--)
System.out.println("...."+Thread.currentThread().getName()+"...."+i);

}
}
public class Xian1
{
static int i;
public static void main(String[] args)
{
RunnableDemo2 t =new RunnableDemo2();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
t1.start();
t2.start();
for(i=0;i<5;i++)
{
System.out.println("...main......"+Thread.currentThread().getName());
}
System.out.println("over");
}
}
运行结果如下:

Java多线程(2)——多线程安全(传智播客毕老师视频讲解)

发现有两个10,且其排序不是按照从大到小输出的,此时这种情况属于多线程安全问题。其原因主要是线程0和线程1抢夺执行权引起的,

即当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行,导致共享数据

的错误。

解决办法:对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可参与执行!

1、同步

同步的前提:1、必须要有两个或者两个以上的线程。

2、必须是多个线程使用同一个锁。


方法1、同步代码块

      synchonized(对象)//对象如同锁。持有锁的线程可以在同步中执行;没有锁的线程即使获取CPU执行权,也进不去。

      {

需要被同步的代码

       }

public class RunnableDemo2 implements Runnable
{
int i=10;
public void run()
{
synchronized(this)
{
for(;i>0;i--)
System.out.println("...."+Thread.currentThread().getName()+"...."+i);
}
}
}
运行结果如下:
Java多线程(2)——多线程安全(传智播客毕老师视频讲解)

看见,此时结果没问题。

方法2、同步函数

public class RunnableDemo2 implements Runnable
{
int i=10;
public void run()
{
while(i>0)
show();
}
public synchronized void show()
{
try{Thread.sleep(100);}catch(Exception e){}
if(i>0)
System.out.println("...."+Thread.currentThread().getName()+"...."+i--);
}
}

运行结果如下:
Java多线程(2)——多线程安全(传智播客毕老师视频讲解)

注意:1、同步函数用的锁是this!

    2、静态同步函数用的锁是Class对象!

  由于静态方法中不能出现this、super关键字,因此其锁不能为this,但可以是任意class对象!

验证代码如下:

public class RunanbleDemo implements Runnable
{
static int i=100;
boolean flag=true;
Object obj=new Object();
public void setValue(boolean flag)
{
this.flag=flag;
}
public void run()
{
if (flag)
{
while(true)
{
synchronized(this) //验证非静态同步函数的锁是this
//synchronized(RunanbleDemo.class)//验证静态同步函数的锁是Class文件
{//同步代码块儿
while(i>0)
{
try{Thread.sleep(10);}catch(Exception e){}
//try{wait();}catch(Exception e){}
System.out.println("...."+Thread.currentThread().getName()+"...."+"Code"+"...."+i--);
}
}

}
}
else
{
while(true)
show();
}
}
public synchronized void show() //非静态同步函数
//public synchronized static void show()//静态同步函数
{
if(i>0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println("...."+Thread.currentThread().getName()+"..............."+"Show"+"...."+i--);
}
}
}
public class Xian1
{
static int i;
public static void main(String[] args)
{
RunanbleDemo t =new RunanbleDemo();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
t1.start();
try{Thread.sleep(10);}catch(Exception e){}
t.setValue(false);
t2.start();
System.out.println("over");
}
}
2、单例设计模式——懒汉式的多线程安全问题
方法1、同步函数

public class Single 
{
private static Single s=null;
private Single(){}
public static synchronized Single getSingle()
{
if (s==null)
s=new Single();
return s;
}
}
方法2、同步代码块(优化版)
public class Single 
{
private static Single s=null;
private Single(){}
public static Single getSingle()
{
if (s==null) //这是其优化的地方,这样保证假如许多线程进来,减少了判断syncronized的过程,优化了代码
synchronized(Single.class)
{
if (s==null)
s=new Single();
}
return s;
}
}
3、死锁
public class DeadLock implements Runnable
{
static int i=100;
boolean flag=true;
Object obj=new Object();
public void setValue(boolean flag)
{
this.flag=flag;
}
public void run()
{
if (flag)
{
while(true)
{
synchronized(DeadLock.class)
{
synchronized(this) //验证非静态同步函数的锁是this
{
if(i>0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println("...."+Thread.currentThread().getName()+"...."+"Code"+"...."+i--);
}
}
}
}
}
else
{
while(true)
{
synchronized(this)
{
synchronized(DeadLock.class)
{
if(i>0)
{
try{Thread.sleep(10);}catch(Exception e){}
System.out.println("...."+Thread.currentThread().getName()+"..............."+"Show"+"...."+i--);
}
}
}
}
}
}
}
public class DeadLockDemo
{
static int i;
public static void main(String[] args)
{
DeadLock t =new DeadLock();
Thread t1=new Thread(t);
Thread t2=new Thread(t);
t1.start();
try{Thread.sleep(10);}catch(Exception e){}
t.setValue(false);
t2.start();
System.out.println("over");
}
}
运行结果为:
Java多线程(2)——多线程安全(传智播客毕老师视频讲解)

即结果在97这儿锁死了,两个线程所持有的锁都不让对方进入,做开发时一定要避免死锁的出现!!