标签:java synchronized 多线程 thread 同步
设计这样一个程序:两个用户去银行存钱,每次存100,存3次,显示银行中总的钱数。
class Bank
{
private int sum;//sum代表银行中钱的总量
public void add (int n)
{
sum += n;
System.out.println("sum = "+sum);
}
}
class Cus implements Runnable
{
private Bank b = new Bank();
@Override
public void run()
{
// TODO Auto-generated method stub
for (int i = 0; i < 3; i++)
{
b.add(100);
}
}
}
public class TONGBUHANSHU
{
public static void main(String[] args)
{
Cus c = new Cus();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
那么该程序有没有安全问题呢?多运行几次发现
输出的结果可能是:
sum = 100
sum = 300
sum = 400
sum = 200
sum = 500
sum = 600
说明该程序存在安全问题。
如何找到问题?
1.明确哪些代码是多线程运行代码
run方法和add方法
2.明确共享数据
b 和 sum
3.明确多线程运行代码中哪些语句是操作共享数据的
class Bank
{
private int sum;
Object obj = new Object();
public void add (int n)
{
synchronized(obj)
{
try
{
Thread.sleep(100);
}
catch (Exception e)
{
// TODO: handle exception
System.out.println(e.toString());
}
sum += n;
System.out.println(" sum = "+sum);
}
}
}
class Cus implements Runnable
{
private Bank b = new Bank();
@Override
public void run()
{
// TODO Auto-generated method stub
for (int i = 0; i < 3; i++)
{
//System.out.print(Thread.currentThread().getName());
b.add(100);
}
}
}
public class TONGBUHANSHU
{
public static void main(String[] args)
{
Cus c = new Cus();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}经过同步代码块之后再运行就不会在出现上面的情况了。
同步代码块的作用就是封装代码,而函数的作用也是封装代码,那么函数封装代码和同步代码块封装代码有什么不同?
唯一的区别就是:同步代码块封装的代码带有同步的特性。
那如果让函数具备了同步的特性?
将 synchronized 关键字作为修饰符放到函数上
这就是传说中的同步函数:
class Bank
{
private int sum;
Object obj = new Object();
public synchronized void add (int n)
{
//synchronized(obj)
// {
try
{
Thread.sleep(100);
}
catch (Exception e)
{
// TODO: handle exception
System.out.println(e.toString());
}
sum += n;
System.out.println(" sum = "+sum);
// }
}
}
class Cus implements Runnable
{
private Bank b = new Bank();
@Override
public void run()
{
// TODO Auto-generated method stub
for (int i = 0; i < 3; i++)
{
//System.out.print(Thread.currentThread().getName());
b.add(100);
}
}
}
public class TONGBUHANSHU
{
public static void main(String[] args)
{
Cus c = new Cus();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
将之前卖票的例子也搞成同步函数的形式。
class Test implements Runnable
{
private int num = 50;
Object obj = new Object();
public synchronized void run ()
{
while (true)
{
// synchronized (obj)
//{
if (num >= 0)
{
try
{
Thread.sleep(20);
}
catch (Exception e)
{
// TODO: handle exception
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+">>"+num--);
}
//}
}
}
}
public class RUNNABLE
{
public static void main (String[] args)
{
Test t = new Test();
Thread a = new Thread(t);
Thread b = new Thread(t);
Thread c = new Thread(t);
Thread d = new Thread(t);
a.start();
b.start();
c.start();
d.start();
}
}
然而输出结果显示全部都是0线程运行的,其他线程没有运行。
为什么?没有弄清楚哪些代码是需要同步的。
需要同步的代码是同步代码块之中的代码,而现在直接将synchronized 关键字作为修饰符放到run方法上,显然与之前用同步代码块的方式时同步的代码是不同的。
解决:
将同步代码块之中的代码封装成函数。
class Test implements Runnable
{
private int num = 50;
// Object obj = new Object();
public void run ()
{
while (true)
{
show ();
}
}
public synchronized void show ()
{
// synchronized (obj)
//{
if (num >= 0)
{
try
{
Thread.sleep(20);
}
catch (Exception e)
{
// TODO: handle exception
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+">>"+num--);
}
//}
}
}
public class RUNNABLE
{
public static void main (String[] args)
{
Test t = new Test();
Thread a = new Thread(t);
Thread b = new Thread(t);
Thread c = new Thread(t);
Thread d = new Thread(t);
a.start();
b.start();
c.start();
d.start();
}
}
同步函数的锁是哪个?
函数需要被对象调用,函数都有一个所属对象的引用
所以同步函数使用的锁是this。
验证:
使用两个线程来卖票,一个线程在同步代码块中
一个线程在同步函数中,都在执行卖票动作
如果同步的话是不会出现错误
class Test implements Runnable
{
private int num = 50;
Object obj = new Object();
boolean flag = true;
public void run ()
{
if (flag)
{
while (true)
{
synchronized (obj)
{
if (num >= 0)
{
try
{
Thread.sleep(20);
}
catch (Exception e)
{
// TODO: handle exception
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+">>--code-- "+num--);
}
}
}
}
else
{
while (true)
{
show();
}
}
}
public synchronized void show ()// 锁是 ?
{
// synchronized (obj)
//{
if (num >= 0)
{
try
{
Thread.sleep(20);
}
catch (Exception e)
{
// TODO: handle exception
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+">> show "+num--);
}
//}
}
}
public class RUNNABLE
{
public static void main (String[] args)
{
Test t = new Test();
Thread a = new Thread(t);
Thread b = new Thread(t);
a.start();
try
{
Thread.sleep(20);
}
catch (Exception e)
{
// TODO: handle exception
}
t.flag = false;
b.start();
}
}
两个线程,a线程运行的是同步代码块中的内容,b线程运行的同步函数中的内容。
输出结果显示有-1号票
说明这个程序时不安全的。
这个程序中已经使用了同步,但是却还是有错误?
考虑使用同步的前提条件:
1.必须有两个或两个以上的线程--(满足)
2.必须使用同一个锁--(??)
同步代码块中的锁是obj,而同步函数中的锁肯定不是obj,我们假设同步函数的锁是this,将同步代码块中的锁也换成this试试。
class Test implements Runnable
{
private int num = 50;
Object obj = new Object();
boolean flag = true;
public void run ()
{
if (flag)
{
while (true)
{
synchronized (this)
{
if (num >= 0)
{
try
{
Thread.sleep(20);
}
catch (Exception e)
{
// TODO: handle exception
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+">>--code-- "+num--);
}
}
}
}
else
{
while (true)
{
show();
}
}
}
public synchronized void show ()// 锁是 this
{
// synchronized (obj)
//{
if (num >= 0)
{
try
{
Thread.sleep(20);
}
catch (Exception e)
{
// TODO: handle exception
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+">> show "+num--);
}
//}
}
}
public class RUNNABLE
{
public static void main (String[] args)
{
Test t = new Test();
Thread a = new Thread(t);
Thread b = new Thread(t);
a.start();
try
{
Thread.sleep(20);
}
catch (Exception e)
{
// TODO: handle exception
}
t.flag = false;
b.start();
}
}
发现输出结果中没有-1号票了,说明该程序安全,也就说明了同步函数的锁是this
静态同步函数的锁是什么?
将show方法声明为静态方法,为了编译通过同时将num声明为静态
class Test implements Runnable
{
private static int num = 50;
Object obj = new Object();
boolean flag = true;
public void run ()
{
if (flag)
{
while (true)
{
synchronized (this)
{
if (num >= 0)
{
try
{
Thread.sleep(20);
}
catch (Exception e)
{
// TODO: handle exception
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+">>--code-- "+num--);
}
}
}
}
else
{
while (true)
{
show();
}
}
}
public static synchronized void show ()// 锁是 this
{
// synchronized (obj)
//{
if (num >= 0)
{
try
{
Thread.sleep(20);
}
catch (Exception e)
{
// TODO: handle exception
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+">> show "+num--);
}
//}
}
}
public class RUNNABLE
{
public static void main (String[] args)
{
Test t = new Test();
Thread a = new Thread(t);
Thread b = new Thread(t);
a.start();
try
{
Thread.sleep(20);
}
catch (Exception e)
{
// TODO: handle exception
}
t.flag = false;
b.start();
}
}
显示结果有-1,程序不安全,说明了静态同步函数锁使用的锁不是this;
静态方法中没有隐含的this。
静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象:类名 .class 该对象的类型是class
class Test implements Runnable
{
private static int num = 50;
Object obj = new Object();
boolean flag = true;
public void run ()
{
if (flag)
{
while (true)
{
synchronized (Test.class)
{
if (num >= 0)
{
try
{
Thread.sleep(20);
}
catch (Exception e)
{
// TODO: handle exception
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+">>--code-- "+num--);
}
}
}
}
else
{
while (true)
{
show();
}
}
}
public static synchronized void show ()// 锁是 this
{
// synchronized (obj)
//{
if (num >= 0)
{
try
{
Thread.sleep(20);
}
catch (Exception e)
{
// TODO: handle exception
System.out.println(e.toString());
}
System.out.println(Thread.currentThread().getName()+">> show "+num--);
}
//}
}
}
public class RUNNABLE
{
public static void main (String[] args)
{
Test t = new Test();
Thread a = new Thread(t);
Thread b = new Thread(t);
a.start();
try
{
Thread.sleep(20);
}
catch (Exception e)
{
// TODO: handle exception
}
t.flag = false;
b.start();
}
}
程序运行安全,说明静态同步的方法,使用的锁是该方法所在类的字节码文件对象:类名.class
Java---14---多线程---synchronized 同步函数
标签:java synchronized 多线程 thread 同步
原文地址:http://blog.csdn.net/u013476556/article/details/42005429