Java线程相关(Thread和Runnable)
随便打开一个应用程序,即使这个程序很小,它也可能是由N多个线程所构成,在没有线程之前,我们用进程作为OS(操作系统)能够拥有资源和独立运行的基本单位。 我们要讨论的线程是比进程更小的,能够独立运行和拥有资源的基本单位。
说到线程,我们就得分析一下一个线程的各种状态,它大体上可以分为以下几种:
1 执行状态:线程获得了处理机正在运行。
2 阻塞状态:线程因为某种原因而暂停运行。
3 就绪状态:线程已经准备好运行,只要分配cpu就可以运行。
既然我们知道了线程能够拥有资源和独立运行的基本单位,那么对于N个线程需要对一个相同的资源进行访问的情况会遇到什么问题呢。让我们看看下面的代码:
public class RunnableTest implements Runnable{
private int a = 0;
public void run() {
while(a>-10){
a--;
System.out.println("a" + "的值为" + a);
}
}
}
public class ThreadTest extends Thread {
private int a = 0;
public void run() {
while (a > -10) {
a--;
System.out.println("a" + "的值为" + a);
}
}
}
上面是实现多线程的两种方法,其中一种为继承Thread类,另一种为实现Runnable接口。但不论哪一种方法,进行下面的测试
public class Test {
public static void main(String[] args) {
ThreadTest thread_0 = new ThreadTest();
new Thread(thread_0).start();
new Thread(thread_0).start();
// RunnableTest rt = new RunnableTest();
// new Thread(rt).start();
// new Thread(rt).start();
}
}
多次运行可能会有一种下面状况。
a的值为-2
a的值为-2
a的值为-3
a的值为-4
a的值为-5
a的值为-6
a的值为-8
a的值为-7
a的值为-9
a的值为-10
出现了两个a的值为-2。我们的计算机是分时操作系统,N个线程并发运行的时候,线程1可能执行到了a--的时候,它的时间片用完了。那么轮到了线程2执行,线程2也要执行a--后运行System.out.println("a" + "的值为" + a);语句,这时候的a就变为-2,如果此时线程2的时间片用完,那么又回到线程1执行,此时该执行System.out.println("a" + "的值为" + a);于是就会得到输出了两次a的值为-2的话。这显然不是我们所预期的。
假设我们利用多线程卖票,这样的话我们可能卖出两张相同的票。这不科学。那么如避免这种情况的发生呢。大体上有下面几种方法:
1:Synchronized关键字。即在方法前面加上关键字synchronized,某个线程在调用被它修饰的方法前会检查是否有其他线程在用此方法,这样可以避免上面的问题。
2:Lock接口。Lock lock = new ReentrantLock();可以得到一个实现Lock的对象。这个可以在方法中给某一部分加锁,也可以实现资源的互斥共享。
public synchronized void run() {
while (a > -10) {
a--;
System.out.println("a" + "的值为" + a);
}
}
private int a = 0;
Lock lock = new ReentrantLock();
public void run() {
while(a>-10){
lock.lock();
a--;
System.out.println("a" + "的值为" + a);
}
}
运行结果为:
a的值为-1
a的值为-2
a的值为-3
a的值为-4
a的值为-5
a的值为-6
a的值为-7
a的值为-8
a的值为-9
a的值为-10
后来经老师提醒我用过lock方法后需要unlock,于是我就对上面的代码做了如下改动:
private int a = 0;
Lock lock = new ReentrantLock();
public void run() {
while (a > -10) {
lock.lock();
try {
a--;
System.out.println("a" + "的值为" + a);
} catch (Exception e) {
} finally {
lock.unlock();
}
}
结果输出却是a从-1到-11。我测试了半天,发现输出a的值为-10之后且执行完lock.unlock()之后又多执行了一个a--。