昨天讲到了如何实现多线程以及多线程的好处,今天我们来看看线程的睡眠sleep(),多线程问题,sleep()是一个静态方法,以毫秒为为单位,我们为什么要使用睡眠呢?那当然是为了我们宝贵的CPU资源能在短时间内为更多的线程服务,而不是在某段时间内一直被某个线程占用。比如某线程在等待一个资源,这个时候我们通常让此线程先阻塞一会,一段时间后继续进入可运行状态,此时如果线程获得了所需的资源则可以继续运行,否则再阻塞,等待资源降临。
通过阻塞我们可以大大的提高CPU的利用率。下面我们来看一个使用sleep()方法的例子
package com.suda.thread;
public class Mythread5 implements Runnable {
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + ",第"
+ (i + 1) + "次使用");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Mythread5 mt = new Mythread5();
Thread thread = new Thread(mt);
thread.start();
}
}
运行上面的代码我们可以看见控制台每隔一秒钟打印出一句话。
在进行线程编程时难免涉及到多线程的问题,那么当多个线程访问一个资源时,就会出现竞争,举个低俗而实际的例子:N多人要上厕所,而厕所只有一个,这时就造成了竞争,如果厕所没有门,那么所有的人都可以进,这样必定造成混乱,影响正常的如厕秩序。我们如何解决呢?就是给厕所加个门。进去一个人就锁起来,别人必须等你解决了才能进去。而在多线程中为了解决这个问题引入了同步加锁方法,使用synchronized来个操作或者方法加锁。下面我们就已售票的例子来看看加锁的必要性:
package com.suda.thread;
public class Mythread_synchronized implements Runnable {
private int ticket = 5;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (ticket > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + ",正在卖出第"
+ (this.ticket--) + "张票!");
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Mythread_synchronized mt = new Mythread_synchronized();
new Thread(mt, "售票员A").start();
new Thread(mt, "售票员B").start();
new Thread(mt, "售票员C").start();
}
}运行结果:
售票员B,正在卖出第5张票!
售票员A,正在卖出第5张票!
售票员C,正在卖出第4张票!
售票员C,正在卖出第3张票!
售票员B,正在卖出第2张票!
售票员A,正在卖出第3张票!
售票员A,正在卖出第1张票!
售票员C,正在卖出第0张票!
售票员B,正在卖出第-1张票!
完全乱了,这就是没加锁的缺陷,十分明显,那我们看看加锁后的方法:
package com.suda.thread;
public class Mythread_synchronized implements Runnable {
private int ticket = 5;
@Override
public void run() {
for (int i = 0; i < 10; i++) {
synchronized (this) {
if (ticket > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ ",正在卖出第" + (this.ticket--) + "张票!");
}
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Mythread_synchronized mt = new Mythread_synchronized();
new Thread(mt, "售票员A").start();
new Thread(mt, "售票员B").start();
new Thread(mt, "售票员C").start();
}
}运行结果:
售票员A,正在卖出第5张票!
售票员A,正在卖出第4张票!
售票员A,正在卖出第3张票!
售票员C,正在卖出第2张票!
售票员C,正在卖出第1张票!
这样就达到了我们正常的结果了。这就是加锁操作,好了,今天先到这儿了,改天继续!