线程不安全:
数据有负数,相同的情况
比如在进行抢票的时候。可能会出现在第数据不准确的现象
public class Unsafe implements Runnable {
private static int ticketNum=10;
private boolean flag=true;
@Override
public void run() {//run 不可以throws异常。
while(flag) {
test();
if(ticketNum<0) {
break;
}
}
}
public static void test() {
try {
Thread.sleep(100);//会出现数据异常的情况。
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--->"+ticketNum--);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//一个资源
System.out.println(Thread.currentThread().getName());//该线程即是main方法。
Unsafe web=new Unsafe();
//多个代理(也即是意味着并发)
new Thread(web,"1").start();
new Thread(web,"2").start();
new Thread(web,"3").start();
new Thread(web,"4").start();
}
}
线程同步:
在访问时加入锁机制。当一个线程获得对象的排他锁,独占资源,其他线程必须等待
- 使用后释放锁即可,
- 但是会存在很多的性能的问题。
- 1.队列,2.锁机制
- synchronize包括两种用法:synchronize方法和synchronize块
public synchronized void test()
synchronize块:synchronized(object){}
修改之后的代码
public class SynBlock implements Runnable{
private static int ticketNum=10;
private boolean flag=true;
@Override
public void run() {//run 不可以throws异常。
while(flag) {
test3();
}
}
//尽可能锁定合理的范围。
//双重检测,主要是为了确定临界值的情况
public void test3() {
if(ticketNum<=0) {//考虑的是没有票的情况。
flag=false;
return;
}
//当多个线程运行到此处时,临界值1,只有一个线程进入同步块,其他的线程在外面等待,当进去的线程执行到
//ticketNum--,所以ticketNum就为0,外面等待的就可以直接return,从而提高了性能。
synchronized(this) {
if(ticketNum<=0) {//考虑的是只剩下最后一张票的情况。
flag=false;
return;
}
try {
Thread.sleep(100);//会出现数据异常的情况。
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--->"+ticketNum--);
}
}
//同步块。
//因为我们需要判断的是ticketnum和flag,但是锁对象只能是一个
//所以向上找,即是SynBlock,所以就是this
//不可以单独锁ticketNum不行,因为ticketNum是一个会变的,因此锁不住
//在进行给对象加锁时,要锁的对象是一个不变的量。
public void test2() {
synchronized(this) {
if(ticketNum<=0) {
flag=false;
return;
}
try {
Thread.sleep(100);//会出现数据异常的情况。
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--->"+ticketNum--);
}
}
//同步方法
//线程安全,同步
//成员方法所得就是this,就是调用该方法的对象。
//锁的是this对象的资源。
public synchronized void test1() {
if(ticketNum<=0) {
flag=false;
return;
}
try {
Thread.sleep(100);//会出现数据异常的情况。
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"--->"+ticketNum--);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//一个资源
System.out.println(Thread.currentThread().getName());//该线程即是main方法。
SynBlock ts=new SynBlock();
//多个代理(也即是意味着并发)
new Thread(ts,"1").start();
new Thread(ts,"2").start();
new Thread(ts,"3").start();
new Thread(ts,"4").start();
}
}