线程同步问题
来源:互联网 发布:哪里有学淘宝拍摄的 编辑:程序博客网 时间:2024/06/11 03:45
线程之间的关系
- 线程间同步:相互竞争 相互排斥
- 线程间协作:线程间相互协作
线程同步
问题引出
一个多线程的程序如果是通过Runnable接口实现的,则意味着类中的属性将被多个线程共享,由此引出资源的同步问题,即当多个线程要操作同一资源时,有可能出现错误。
练习: 分别使用两种编程方法实现买票的程序
1. 继承Thread方法
public class TestTicketThread{ public static void main(String[] a){ TicketThread tThread1 = new TicketThread(); TicketThread tThread2 = new TicketThread(); TicketThread tThread3 = new TicketThread(); tThread1.start(); tThread2.start(); tThread3.start(); }}class TicketThread extends Thread { private int ticket = 5; public void run(){ for (int i = 0; i < 5; i++){ if (ticket > 0){ System.out.println(this.getName() + "卖票:ticket = " + ticket--); } } }}
运行结果:每个线程单独买票
- 实现Runnable接口
package zhi;/** * Created by admin on 2017/5/17. */public class TestTicketRunnable{ public static void main(String[] a){ TicketRunnable Thread = new TicketRunnable(); new Thread(Thread).start(); new Thread(Thread).start(); new Thread(Thread).start(); }}class TicketRunnable implements Runnable { private int ticket = 5; @Override public void run() { for (int i = 0; i < 5; i++){ if (ticket > 0){ System.out.println(Thread.currentThread().getName() + "卖票:ticket = " + ticket--); } } }}
运行结果:
Thread-0卖票:ticket = 5
Thread-0卖票:ticket = 2
Thread-2卖票:ticket = 3
Thread-1卖票:ticket = 4
Thread-0卖票:ticket = 1
- 结果分析
第二种方法,虽然启动了3个线程,但是3个线程一共卖了5张票,即ticket属性被所有的线程对象共享。而第一种方法,3个线程各卖了5张票,没有实现属性的共享。
结论:实现Runnable接口的方法相对于继承Thread类来说,适合多个相同程序代码的线程去处理统一资源的情况。
练习: 在上述卖票事例的基础上,做如下修改
public class TestTicketRunnable{ public static void main(String[] a){ TicketThread tThread = new TicketThread(); new Thread(tThread).start(); new Thread(tThread).start(); new Thread(tThread).start(); }}class TicketThread implements Runnable { private int ticket = 5; public void run(){ for (int i = 0; i < 5; i++){ if (ticket > 0){ try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "卖票:ticket = " + ticket--); } } }}
运行结果:
Thread-0卖票:ticket = 5
Thread-2卖票:ticket = 5
Thread-1卖票:ticket = 4
Thread-1卖票:ticket = 2
Thread-2卖票:ticket = 3
Thread-0卖票:ticket = 3
Thread-0卖票:ticket = -1
Thread-1卖票:ticket = 1
Thread-2卖票:ticket = 0
分析:卖票的业务步骤如下:
1. 判断票数是否大于0,大于0则表示还有票可以卖;
2. 如果票数大于0,则将票卖出。
在上面的代码中,在步骤(1)和(2)之间加入了延迟操作,那么一个线程就有可能在判断完之后,还没有对票数进行减操作之前,其他线程就已经将票数减少了,这样一来就会出现票数为负的情况。
要解决这个问题,必须使用同步。同步是指多个操作在同一个时间段内只能有一个线程进行,其他线程要等待此线程完成之后才可以继续执行。
使用synchronized同步代码块——隐式加锁
为避免竞争状态,应该防止多个线程同时进入程序的某一个特定的部分,程序中的这部分称为临界区。
第一种方法可以在代码块上加上synchronized关键字,则此代码块就称为同步代码块。
同步代码块同一时刻只能有一个线程访问
练习: 修改上面的代码,用同步机制解决资源共享问题
public class TestTicketRunnable{ public static void main(String[] a){ TicketThread tThread = new TicketThread(); new Thread(tThread).start(); new Thread(tThread).start(); new Thread(tThread).start(); }}class TicketThread implements Runnable { private int ticket = 5; public void run(){ for (int i = 0; i < 5; i++){ synchronized(this){ if (ticket > 0){ try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "卖票:ticket = " + ticket--); } } } }}
运行结果:
Thread-0卖票:ticket = 5
Thread-0卖票:ticket = 4
Thread-2卖票:ticket = 3
Thread-2卖票:ticket = 2
Thread-2卖票:ticket = 1
分析:使用同步代码块之后,没有出现重复票和票为负数的情况。
在方法前加入synchronized关键字,则该方法为同步方法。
public class TestSynchronizedMethod { public static void main(String[] a){ TicketThreadMethod tThread = new TicketThreadMethod(); new Thread(tThread).start(); new Thread(tThread).start(); new Thread(tThread).start(); }}class TicketThreadMethod implements Runnable { private int ticket = 5; public void run(){ for (int i = 0; i < 5; i++){ this.sale(); } } public synchronized void sale(){ if (ticket > 0){ try { Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "卖票:ticket = " + ticket--); } }}
利用加锁同步——显式加锁lock.lock()
线程协作在研究
- 线程/进程同步问题
- 线程同步问题2
- 关于线程同步问题
- 线程的同步问题
- Synchronzied 线程同步问题
- 线程同步问题
- 线程之间同步问题
- 线程同步问题
- 线程同步的问题
- 线程同步问题
- linux线程同步问题
- 线程同步问题
- C# 线程同步问题
- MFC 线程同步问题
- 【转】线程同步问题
- 线程同步问题
- 线程同步问题
- synchronized线程同步问题
- 1074. Reversing Linked List (25)
- 爱测未来开发-Flask:从Hello World到大型应用 (一)
- JqueryEasyUI之DataGrid扩展
- JVM-Minor GC、Major GC和Full GC之间的区别
- java在线自动升级最新版与Eclipse在线自动升级最新版本
- 线程同步问题
- 【个人笔记重点,不作为参考】主题:立即执行函数
- httpClient学习整理
- Scala学习一:基础
- Java命令学习系列
- RecyclerView实现查看更多及收起
- JQueryMolibe事件
- 如何寻找出微信官方的微信指数API ?
- maven项目添加jar包