<div class="iteye-blog-content-contain" style="font-size: 14px"></div>
这个总结将对线程中的资源共享和线程同步问题进行简单的分析。
线程:是进程中的一个单一的连续控制流程。
一个进程可以含有多个线程,那下面就谈谈多线程。
java中多线程的实现有两种手段:1 继承Thread类 2实现Runnable接口
这里以买火车票为例。
class Ticket extends Thread {
public int tickets = 10;
public String name;
public Ticket(String name){
this.name = name;
}
public void run(){
for(int i=0;i<10;i++){
System.out.println(this.name+"买票"+this.tickets--);
}
}
}
public class Test1 {
public static void main(String []arg){
Ticket t1 = new Ticket("线程1");
Ticket t2 = new Ticket("线程2");
Ticket t3 = new Ticket("线程3");
t1.run();
t2.run();
t3.run();
}
}
看到运行结果了吧,它们都是顺序执行的,这说明我们的调用方法不对,当我们把run方法改为start方法后才出现我们想要的结果.那我们来看看run方法和start方法的区别。
run()方法:在本线程内调用该Runnable对象的run()方法,可以重复多次调用;
start()方法:启动一个线程,调用该Runnable对象的run()方法,不能多次启动一个线程;
run()方法只是一个普通的方法,如果直接调用run方法的话那程序中还是只有一个主线程,并没有达到多线程的目的,主程序中还是会顺序执行,执行完一个run方法后才会继续执行下一个方法。而start()方法是负责启动一个线程,不用等待执行完其中的run方法后再执行下面的方法,而是直接执行下面的方法。简单的说就是你在run方法中写入要执行的代码,然后你只要调用start方法就可以了,至于什么时候执行run方法,那就不是你负责的了。start()方法的功能其实是向cpu申请另一个线程空间来执行run()方法的,它和当前的线程空间是相对独立的。就是说如果你直接调用run方法的话它仍然会执行,但是在当前的线程空间,所以它会按顺序执行,而调用start方法后,run方法就会和当前的代码并行的执行,从而达到多线程。
另一个我们要考虑的问题就是资源共享问题。这个问题也可以用来区别Thread和Runnable,而多线程在很多情况下都是处理资源共享的问题。下面我们仍以买火车票为例来看看资源共享的问题。
class Ticket extends Thread {
public int tickets = 10;
public String name;
public void run() {
while (this.tickets > 0) {
System.out.println(this.name + " 卖票:" + this.tickets--);
}
}
public Ticket(String name) {
this.name = name;
}
}
public class Test1 {
public static void main(String[] arg) {
Ticket t1 = new Ticket("线程1");
Ticket t2 = new Ticket("线程2");
Ticket t3 = new Ticket("线程3");
t1.start();
t2.start();
t3.start();
}
}
对于这个的运行结果我们之前已经试过了,从结果上看,它虽然实现了多线程,但它好像并不符合实际,我们定义一共有10张票,分三个地方来买,那就是说三个地方共享这10张票,可结果出现了30个数,显然是不对的,那如果把代码改一下:
class Ticket implements Runnable {
public int tickets = 10;
public String name;
public void run() {
while (this.tickets > 0) {
System.out.println("卖票:" + this.tickets--);
}
}
}
public class Test1 {
public static void main(String args[]) {
// 准备四个售票点
Demo d = new Demo();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
Thread t3 = new Thread(d);
t1.start();
t2.start();
t3.start();
}
}
再运行,结果:
卖票:10
卖票:9
卖票:8
卖票:7
卖票:6
卖票:5
卖票:4
卖票:3
卖票:2
卖票:1
资源共享的问题也算是解决了。
还有一个问题就是线程同步的问题,这也是值得我们注意的问题,把上面的代码再进行修改:
class Demo implements Runnable {
private int ticket = 10;
public void run() {
while (this.ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("卖票:" + this.ticket--);
}
}
};
public class Test1 {
public static void main(String args[]) {
// 准备四个售票点
Demo d = new Demo();
Thread t1 = new Thread(d);
Thread t2 = new Thread(d);
Thread t3 = new Thread(d);
t1.start();
t2.start();
t3.start();
}
};
运行结果:
卖票:10
卖票:9
卖票:8
卖票:7
卖票:6
卖票:5
卖票:4
卖票:3
卖票:2
卖票:1
卖票:0
卖票:-1
出现了两个不该出现的结果,那我们来分析一下出现这个结果的原因。
我们分三个售票点共同买10张票,当票数只剩一张的时候,假如被A拿走了,然后进入sleep中,而在这个时候,B也将最后一张票拿走了,而此时的tickets还等于1,当A把tickets放回的时候,tickets--变为了0,当B再放回的时候则出现了-1的情况。这就是不用步造成的。
那我们就要解决这个不同步的问题
下面介绍一下synchronized关键字:
当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
当两个并行的线程同时访问object的一个synchronized修饰的同步块是,同一时间只能有一个线程可以对其访问,只有当他访问完之后,另一个才能对其访问。
建立一个同步方法:
class Demo implements Runnable {
private int ticket = 10;
public synchronized void method(){
while (this.ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" 卖票:" + this.ticket--);
}
}
public void run() {
method();
}
};
public class Test1 {
public static void main(String args[]) {
// 准备四个售票点
Demo d = new Demo();
Thread t1 = new Thread(d,"a");
Thread t2 = new Thread(d,"b");
Thread t3 = new Thread(d,"c");
t1.start();
t2.start();
t3.start();
}
};
运行结果:
b 卖票:10
b 卖票:9
b 卖票:8
b 卖票:7
b 卖票:6
b 卖票:5
b 卖票:4
b 卖票:3
b 卖票:2
b 卖票:1
这个结果虽然对票数同步了,但似乎又出现了其他的问题,一个售票点就把所有的票卖完了,回头看看我们的代码是哪里出了问题。
做如下改正:
class Demo implements Runnable {
private int ticket = 10;
public synchronized void method() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 卖票:"
+ this.ticket--);
}
public void run() {
while (this.ticket > 0) {
method();
}
}
};
运行结果:
a 卖票:10
a 卖票:9
a 卖票:8
a 卖票:7
a 卖票:6
a 卖票:5
c 卖票:4
c 卖票:3
b 卖票:2
b 卖票:1
c 卖票:0
a 卖票:-1
又出问题了(无奈),看看又是什么情况,我们在同步方法中加一个if(this.tickets>0)保护,在运行,看看结果吧... ...终于没问题了。