又是忙碌的一天,Java结束了复习,老师也开始讲新的课程了。下午下课,很任性的没有去吃饭,后来与老师讨论时就说到了线程同步的问题。有了点自己的感触,想给大家分享一下,希望能让像我一样的程序员能有所收获。
我们都知道,多线程编程为程序开发带来了很多的便利,但是也带来了一些问题,这些问题时在程序开发过程中必须进行处理的。这些问题的核心是,如果多个线程同时访问一个资源,如变量、文件等,如何保证访问安全?
举个例子,假设有两个线程:线程A和线程B,并且程序为这两个线程开辟了一个公共的内存空间,情况则是线程B写一次,线程A读一次。那么则会出现如下几种情况:
1.在某个时候线程B运行速度比较快,在线程A未读取上一个数据之前,B就写了第二次数据,造成数据遗漏。
2.在某个时候线程A运行速度比较快,它读完一次数据之后,线程B还没来得及写,线程A又来读第二次。结果线程A读不到数据,导致运行出错。 3.线程B正在写数据时,线程A也来读取数据,这时可能线程B还没将数据写完,线程A将数据读走,导致程序出错。 接下来,就让我用代码来演示同步产生的错误的情况: 利用线程来模拟售票系统: 票类:public class Tickets {
public int total;//在票这个类中定义票的数量
public Tickets(int total){//初始化
this.total=total;
}
public void action(String threadName){
System.out.println(threadName+"卖票之前"+total);
total--;
System.out.println(threadName+"卖票之后"+total);
}
}
线程类:
public class TicketsThread extends Thread{
private Tickets tickets;//票的对象
public TicketsThread(Tickets tickets) {//初始化票的对象
this.tickets=tickets;
}
@Override
public void run() {
while(true){
if(tickets.total<=1){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
tickets.action(Thread.currentThread().getName());
}
}
}
测试类:
public class Test {通过测试类的运行结果为:
public static void main(String[] args) {
Tickets t=new Tickets(10);
TicketsThread tt1=new TicketsThread(t);
tt1.start();
TicketsThread tt2=new TicketsThread(t);
tt2.start();
}
}
从结果来看,明显在我用荧光笔标识的地方有错误,明显这里应该是“Thread-0卖票之前3”,也就是读到了“脏数据”(就是不该读到的数据),再把测试类反复运行,总难免会有一些读错数据的情况,那么我们就不难发现线程在同步中也会产生一些无法预料的错误,那么究竟该怎么解决呢? <注:在这里,我并没有说每次测试都是错误的,但是完全正确的几率十分低> 在多线程编程中,这种被多个线程同时访问的资源叫做临界资源,那么解决临界资源问题,最基本、最简单的思路就是使用同步关键字synchronized。 因为我们同时访问的所谓临界资源就是票这个类,所以只需要改正这里即可,以下是代码:
public class Tickets {
public int total;//在票这个类中定义票的数量
public Tickets(int total){//初始化
this.total=total;
}
public synchronized void action(String threadName){//定义同步化,即线程A访问时,线程B必须等待;线程B访问时,线程A必须等待
System.out.println(threadName+"卖票之前"+total);
total--;
System.out.println(threadName+"卖票之后"+total);
}
}
再让我们来看看输出的结果: 那么,这个关键字的作用到底是什么呢?让我们再回到我一开始举的例子上,我们可以这样理解,当有此关键字存在时“定义同步化,即线程A访问时,线程B必须等待;线程B访问时,线程A必须等待”。 希望能给一些和我一样的初学者一些帮助,也希望技术大牛们多多指点。