一、多线程的安全问题
分析下图可知,当tickets为1的时候,Thread-0执行run方法,在执行tickets--之前,Thread-1也执行了run方法。此时就会产生错误
1、多线程安全问题产生的原因:
1、线程任务中有处理到共享的数据。
2、线程任务中有多条对共享数据的操作。
总结:一个线程在操作共享数据的过程中,其他线程参与了运算,操作了共享数据,造成了数据的错误。
2、解决的思想
只要保证多条操作共享数据的代码在某一时间段,被一条线程所执行,在执行期间不允许其他线程参与运算。
3、如何解决
用同步代码块来解决
synchronized(对象)
{
需要被同步的代码。
}
需要被同步的代码。
}
执行时,线程0首先判断obj对象是否存在,如果对象存在,那么线程0持有该对象,线程0执行同步代码块中的代码,此时其他线程无法持有obj对象
只有当线程0执行完毕,释放obj对象,其他线程才能获得该对象并执行。可以类比火车上的卫生间进行理解。
同步中的锁机制:
同步在目前情况下保证一次只能有一个线程在执行,其他线程进不来,这就是同步的锁机制。
二、同步的好处和弊端
好处:解决了多线程的安全问题。
弊端:消耗资源,降低执行效率。这种效率在可接受范围之内。
三、同步的前提
多个线程在同步中必须使用同一个锁,这才是对多个线程同步。
注意:多个线程:同步针对两个以上线程,单线程中加锁就失去了意义。
同一个锁:只有使用同一个锁才能正常执行。
根据同步的前提来解决程序中加了同步而没有解决多线程安全问题的问题。
四、同步、并发
线程任务中有很多代码,不能同步所有代码,如果同步所有代码和单线程就没有区别了。只同步操作共享数据的代码。
五、 同步的完整实例:
两个储户,到同一银行存钱,每个人存了3次,一次100.
分析:
1、描述银行
2、描述储户任务
</pre><pre name="code" class="java">class Bank{ private int sum; private Object = new Object(); //线程任务,sum是共享数据,并有多条操作共享数据的代码,故要同步 public void add(int i){ //obj类型是任意的,只要保证多个线程用同一个对象即可。 synchronized(obj){ sum = sum + i; System.out.println("sum="+sum); } } } class Customer implements Runnable{ private Bank b = new Bank(); //线程的任务 public void run(){ for(int x = 0; x<3;x++){ //b是共享数据,但没有多条代码进行操作,所以不用同步 b.add(100); } } } class ThreadTest{ public static void main(String[] args){ //创建任务对象 Customer c = new Customer(); //创建线程对象 Thread t1 = new Thread(c); Thread t2 = new Thread(c); //开启线程 t1.start(); t2.start(); } }