线程同步
1.线程同步定义
所谓线程同步,它的真实意思,其实是“排队”,几个线程要对同一资源进行操作时,必须排队依次来进行访问,而不是在同一时刻多个线程对共享资源同时操作。
2.问题引入
至于为什么要运用线程同步呢?就如我们在多线程(一)中提到的例子买火车票一样,如果多个线程同时去买票就有可能出现余票为负数的情况。
示例代码如下:
public class RunaableTest implements Runnable{
int ticket=5;
public static void main(String []args){
RunaableTest rt=new RunaableTest();
for(int i=0;i<3;i++){
new Thread(rt).start();
}
}
public void run(){
while(true){
if(ticket>0){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"买票之后还有余票:ticket"+ticket--+"张");
}
}
}
}
程序运行结果如下:
由以上例子可以看出,当我们让线程休眠一段时间,再去执行ticket--,这样在程序的最后出现了卖出负票的问题,这样显然是不对的,为什么会这样呢?我们可以猜测:在if循环中同一时刻至少存在两个线程,第一个线程还没来得及进行ticcket--操作时,第二个线程经过判断满足if循环条件即ticket>0也进入循环体内,这样一来就会出现其实没票了,但还能卖出票的情况。
3.解决办法
出现上面的问题,只是因为多个线程对if循环的条件同时进行了判断,所以在多线程操作同一个资源时我们只需要对其有一个限制,即设定同一时刻只能有一个线程去访问共享的资源,如此一来问题就可以轻松的解决了。
而在JAVA中我们可以通过关键字synchronized来解决这个问题,实现线程之间的同步。而synchronized的使用方法有两种,可以通过同步代码块和同步方法两种方式来完成。
1.同步代码块:
public void run(){
while(true){
synchronized(this){
if(ticket>0){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"买票之后还有余票:ticket"+ticket--+"张");
}
}
}
}
2.同步方法:
public synchronized void run(){
while(true){
if(ticket>0){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程"+Thread.currentThread().getName()+"买票之后还有余票:ticket"+ticket--+"张");
}
}
}
两种实现方式的运行结果是一样的,结果如下:
由此我们便可完成线程同步,解决多个线程同一时刻访问同一对象的问题啦!!!
PS:线程中还有死锁的概念,所谓死锁,就是指两个线程都在等对方完成。举个例子,假设只有一碗饭,一双筷子,二者合到一起,才能吃到饭,但是饭在甲的手中,而筷子在乙的手中,甲,乙都在等着对方先给,就这样僵持着,最终的结果是甲乙都吃不到饭,这就是死锁的概念。程序出现死锁的情况有可能是因为过多的同步,所以在多个线程共享同一资源进行同步的同时,也要注意避免出现死锁的状况哈。。。。。。