多线程的出现,使得多个功能能够同时工作,但是也带来了问题。
实例说明:
class MyThread implements Runnable
{
private int num=1;
public void run()
{
if(num>0)
System.out.println("num="+(num--));
}
}
class Demo
{
public static void main(String[] args)
{
MyThread t=new MyThread();
Thread t1=new Thread(t);
Thread t2=new Thread(t);//这里t1,t2公用一个对象t,所以t.num是t1,t2共享数据
t1.start();
t2.start();
}
}
==============================================================================
分析:
如果线程1做完判断if(num>0)后就切换到线程2去做判断,在这过程中num并没有被处理过,
此时的num=1,那么就会输出1和0,0并不是我们希望的数据。
问题产生的原因:当多条语句在操作多线程共享数据时(比如例子中的num),若其中一个线程只执行了其中的一部分,cpu就切换到另一个线程去执行那些语句,这时就会产生共享数据的处理错误。
处理办法:引入同步代码块
格式:
synchronized(对象)
{
需要同步的代码(操作多线程共享数据的语句);
}
修改后的代码:
class MyThread implements Runnable
{
private int num=1;
Object obj=new Object();
public void run()
{
synchronized(obj)//对象可以随意给。。
{
if(num>0)
System.out.println("num="+(num--));
}
}
}
class Demo
{
public static void main(String[] args)
{
MyThread t=new MyThread();
Thread t1=new Thread(t);
Thread t2=new Thread(t);//这里t1,t2公用一个对象t,所以t.num是t1,t2共享数据
t1.start();
t2.start();
}
}
==============================================================================
效果:
执行同步代码块在被线程执行时,只有当一个线程把同步代码块中的语句全部执行完,其
他线程才能执行
同步代码块并不是越多越好,思考一下,如果整个run方法都同步,那么就相当于单线程。
需要同步的前提:
1,必须要有多个线程执行同步的代码。
2,同步的代码必须要有对线程共享数据的操作。
========================================================================================================
除了,同步代码块,还有一种同步的方法,那就是同步函数。
当需要同步的代码正好是一个函数时,只要用synchronized关键字去修饰该函数就能使得该函数具有同步的性质,即一个线程没有执行完该函数,其他线程就不能执行该函数。
上诉实例修改:
class MyThread implements Runnable
{
private int num=1;
public synchronized void run()
{
if(num>0)
System.out.println("num="+(num--));
}
}
class Demo
{
public static void main(String[] args)
{
MyThread t=new MyThread();
Thread t1=new Thread(t);
Thread t2=new Thread(t);//这里t1,t2公用一个对象t,所以t.num是t1,t2共享数据
t1.start();
t2.start();
}
}
不过同步函数也有局限性,就是他要求整个函数都需要同步时才使用,如果一个函数中只有其中一小部分代码需要同步,那应该优先选用同步代码块。
========================================================================================================================
如果共享数据被static修饰,那么同步代码块使用格式应该改为:synchronized(所在类类名.class)
========================================================================================================================
同步代码块中的对象参数相当于一把锁,每当有线程进入,“锁”就标记一次,出来时去掉标记,从而保证代码块中不会同时存在多个线程,因此,如果你想让多个同步代码块实现同步的效果,即多个同步代码块中不会同时存在多个线程,那么只要让这几个同步代码块传入同一个参数对象即可,而同步函数相当于一个参数对象为this的同步代码块。