本篇由于涉及多线程操作,所以线程是使用实现Runnable接口来创建的。
在上篇所示线程任务中,我们不难发现,是存在三步操作的:
第一:打印语句;
第二:计算sum=sum-1;
第三:线程休眠。
那么,在多线程操作中,可能会出现,第一个线程准备打印,还没有进行sum=sum-1计算时,第二个线程也开始打印语句了,
那么此时第二个线程打印语句中的sum值由于还没有经过线程1处理,所以线程二打印的语句也会是“还剩49个苹果”,要解决
这个问题,就引入了线程同步概念,将线程中的所有操作(任务)视为同步处理,是不分先后的。那么,只要线程1比线程2早
开启,哪怕是1纳秒,线程2中num的初始值也是49,所以线程2输出语句是“还剩48个苹果”,线程同步有三种方法。这里只针对
具体任务贴出同步代码操作。
1.同步代码块
public void eat() {
synchronized (this) {
if (sum1 > 0) {
System.out.println(Thread.currentThread().getName() + "吃了一个苹果," + "还剩" + --sum1 + "个苹果");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
这里的this指向一个同步监听对象,可以理解为一个多线程共享资源,也就是Runnable的实例。
2.同步方法
synchronized public void eat() {
if (sum1 > 0) {
System.out.println(Thread.currentThread().getName() + "吃了一个苹果," + "还剩" + --sum1 + "个苹果");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
由于run方法不能用synchronized修饰,只能新建一个该修饰符修饰的方法,放到run里面执行。
3.同步锁(Lock)
final Lock lock = new ReentrantLock(); public void eat() {
lock.lock(); //拿锁关门
if (sum1 > 0) {
System.out.println(Thread.currentThread().getName() + "吃了一个苹果," + "还剩" + --sum1 + "个苹果");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); //开锁
}
}
}
这里,先在类里面定义一个锁对象,然后在进入任务之后拿锁锁上,任务结束,开锁,别的线程拿到锁才能进入任务操作。