多线程(线程安全问题)
这里以买票为例:
继承Thread的第一种创建线程的方法,不易满足多个线程共享一块数据资源的需求。
所以采用实现Runnable接口的第二种方法来创建线程。
class Ticket implements Runnable{
private int num = 100;
public void run() {
sale();
}
public void sale (){
while(true){
if(num > 0)
{
try{Thread.sleep(10);}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"****"+num);
num --;
}
}
}
}
class ThreadDemo {
public static void main (String[] arg){
Ticket d = new Ticket();
Thread t1= new Thread(d);
Thread t2 = new Thread(d);
Thread t3 = new Thread(d);
Thread t4 = new Thread(d);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
看似没有问题实际是有线程问题的;
仔细分析下面这段代码:
cup是随机指向不同的线程,当t1线程刚进入if的代码块,还没有执行System输出语句,这是cup指向了t2,这个时候t2也会进入到if代码块,,t3,t4一样的道理。
此时,每个线程都可以执行System的买票代码,这样num就会小于0;
if(num > 0)
{
try{Thread.sleep(10);}catch(InterruptedException e){}//为了模式线程问题的场景
System.out.println(Thread.currentThread().getName()+"****"+num);
num --;
}
解决线程问题的方法:同步代码块。
synchronized(对象){}//这个对象类似于一个开关,没有线程进入代码块开关是开,有线程进入代码块开关是关,别的线程智能等待。
class Ticket implements Runnable{
private int num = 100;
Object obj = new Object();
public void run() {
sale();
}
public void sale (){
while(true){
synchronized(obj){
if(num > 0)
{
try{Thread.sleep(10);}catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName()+"****"+num);
num --;
}
}
这样就解决了线程安全的问题。
}
}
}
线程安全问题产生的原因:
1.多个线程操作共享的数据。
2.操作共享数据的线程代码有多条。
同步的好处和弊端:
好处:解决线程安全问题。
弊端:相对降低了执行cpu效率,因为外部的线程都会判断同步锁无效。
同步的前提:多个线程必须使用的是同一个锁,就是synchronized(对象)的对象。