编辑器:Notepad++;学习视频:毕向东Java基础教程
(1)多线程的安全隐患(判断原则)
- 多个线程在操作共享的数据
- 操作共享数据的代码有多条
(2)当一个线程在执行操作共享数据的多条代码过程中,其他线程参与运算,就会导致线程安全问题的产生。
- 解决思路:将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程不可以参与运算,必须要当前线程把这些代码执行完毕后,其他线程才可以参与运算
- 在Java中用同步代码块解决这个问题格式:synchronized(对象){ 需要同步的代码块 }
(3)同步的好处与弊端:
- 好处:解决了线程安全问题
- 弊端:降低了效率,因为同步外的线程都要判断同步锁
(4)同步的前提
- 必须保证有多个线程并使用同一个锁
(5)同步函数使用的锁是this
(6)同步函数和同步代码块的区别
- 同步函数使用的锁是this
- 同步代码块的锁是任意对象,建议使用同步代码块
代码示例:
/*
验证同步函数的锁
同步函数的锁与同步代码块的锁是不同的
*/
//第一步:实现Runnable接口
class Ticket implements Runnable //不使用继承,避免多个线程卖相同的票(可将num定义成静态的来解决)
{
private int num = 100; //卖100张票
boolean flag = true;
//Object obj = new Object();
//第二步:覆盖run方法
public void run()
{
if(flag)
{
while(true)
{
//synchronized(obj)
synchronized(this)
{
if(num>0)
{
try{Thread.sleep(14);}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"...synCodeBlock...sale-"+num--);
}
}
}
}
else
{
while(true)
{
this.show(); //同步函数的锁,this
}
}
}
public synchronized void show()
{
if(num>0)
{
try{Thread.sleep(14);}catch(InterruptedException e){} //产生线程安全问题
System.out.println(Thread.currentThread().getName()+"...synFunc...sale-"+num--);
}
}
}
class SynFunClock
{
public static void main(String[] args)
{
//第三步:实例化Runnable接口子类对象,并作为参数传递给Thread
Ticket t = new Ticket(); //只需要实例化一次ticket类,如果继承,需要几个线程,就得实例化几次,导致一张票卖多次的问题
Thread t1 = new Thread(t);
Thread t2 = new Thread(t);
//第四步:调用start()方法,开启线程
t1.start();
try{Thread.sleep(14);}catch(InterruptedException e){}
t.flag = false;
t2.start();
}
}