多线程的安全的原因
1.多个线程在操作共享的数据
2.操作共享数据的代码有多条
当一个线程再行操作共享数据的多条语句,其他线程参与了运算
问题:
在一个程序中有一个数据被多条线程所操作,导致结果出错如何避免(不同步)
示例代码:
public class Text_Thread
{
public static void main(String[] args)
{
TicketOfRunnable t1 = new TicketOfRunnable();
TicketOfRunnable t2 = new TicketOfRunnable();
Thread a = new Thread(t1);
Thread b = new Thread(t1);
Thread c = new Thread(t1);
Thread d = new Thread(t1);
//定义四个线程类的对象,
a.start();
b.start();
c.start();
d.start();
//将四个线程对象开启
}
}
class TicketOfRunnable implements Runnable
{
private int IDnumber = 5;
public void run()
{
while(true)
{
if(IDnumber > 0)
{
try
{
Thread.sleep(10);//让线程休眠一小会
}
catch (InterruptedException e)
{}
//让线程休眠的目的是降低不同的线程切换的速度 System.out.println(Thread.currentThread().getName()+"...."+IDnumber--);
}
}
}
}
运行结果:
Thread-0….4
Thread-1….5
Thread-3….2
Thread-2….3
Thread-1….0
Thread-2….1
Thread-3….-1
Thread-0….-2
//出现了小于等于0的结果
解决方法:
将多条共享数据的代码封装起来,当有线程在执行这些代码的时候,其他线程不能进入,执行完毕之后,其他线程才能参与运算
关键字
synchronized(obj) //这个代码块是有参数的(对象)
{ 所要封装的代码块 }
示例代码:
public class Text_Thread
{
public static void main(String[] args)
{
TicketOfRunnable t1 = new TicketOfRunnable();
TicketOfRunnable t2 = new TicketOfRunnable();
Thread a = new Thread(t1);
Thread b = new Thread(t1);
Thread c = new Thread(t1);
Thread d = new Thread(t1);
a.start();
b.start();
c.start();
d.start();
}
}
class TicketOfRunnable implements Runnable
{
private int IDnumber = 5;
Object obj = new Object();
public void run()
{
while(true)
{
synchronized(obj)
{
if(IDnumber > 0)
{
try
{
Thread.sleep(10);//让线程休眠一小会
}
catch (InterruptedException e)
{}
System.out.println(Thread.currentThread().getName()+"...."+IDnumber--);
}
}
}
}
}
运行结果:
运行结果:
Thread-0….5
Thread-2….4
Thread-2….3
Thread-2….2
Thread-2….1
1.如果即使使用了同步锁还是没有解决问题考虑下面的问题
同步的前提:必须有多个线程使用同一个锁
一把对象锁的实现:
class TicketOfRunnable implements Runnable
{
private int IDnumber = 5;
Object obj = new Object(); //只创建一次这个对象
public void run()
{
while(true)
{
synchronized(obj)
{
。。。。。。
}
}
}
//正确可以确保同步
错误的使用多把对象锁示例:
class TicketOfRunnable implements Runnable
{
private int IDnumber = 5;
public void run()
{
Object obj = new Object();//随着线程的进入都要进行对象创建(相当于多锁)
while(true)
{
synchronized(obj)
{
....
}
}
}
2.同步函数
关键字synthrontic直接放在函数的关键字中
…
public synchronized void add(int num) //同步函数
…
同步函数的锁
功能也是实现同步,但是同步函数的锁与同步代码块的锁不是同一个锁,同步函数的锁就是在创建线程是传入的对象(this)
示例代码:
public class SynFunctionLockDemo
{
public static void main(String[] args)
{
TicketOfRunnable t1 = new TicketOfRunnable();
Thread a1 = new Thread(t1);
Thread a2 = new Thread(t1);
a1.start();
try{Thread.sleep(10);} catch(InterruptedException e) {} //让主线程进入睡眠
t1.FLAG = false;
a2.start();
}
}
3.静态同步方法(锁)
静态函数直接就加载进方法区是字节码文件对象(getClass)
获取字节码文件对象:
Class clazz = TicketOfRunnable.class
//获取字节码文件的对象
class calzz = t1.getClass();
//创建了对象以后来获取字节码文件对象
介绍一种可以切换同步代码块与同步函数的方法
示例代码:
class TicketOfRunnable implements Runnable
{
private int IDnumber = 5;
Object obj = new Object();
boolean FLAG = true;
public void run()
{
if(FLAG)
{
while(true)
{
synchronized(obj)
{
fun("同步代码块");
}
}
}
else
{
while(true)
show();
}
}
public synchronized void show()
{
fun("同步函数");
}
//将原来的代码中重复的部分进行抽取,用函数封装起来
运行结果:
Thread-0….同步代码块5
Thread-0….同步代码块4
Thread-1….同步函数4
Thread-1….同步函数3
Thread-0….同步代码块3
Thread-1….同步函数2
Thread-0….同步代码块2
Thread-1….同步函数1
Thread-0….同步代码块1