JAVA学习——多线程同步

来源:互联网 发布:网络型数据采集机 编辑:程序博客网 时间:2024/05/18 01:33

上一篇对多线程的基本用法进行了简单的小结,这一篇着重说一下多线程同步问题


使用多线程,由于多线程并发执行的特点,所以大大的提高了程序的运行效率,但是,当多个线程去访问同一个资源时,也会出现一些安全问题

就拿我们之前所说过的售票案例。

/** * 模拟窗口售票 *  * @author Shawn·Zhang */public class Example01 {public static void main(String[] args) {TicketWindow tw = new TicketWindow();new Thread(tw, "售票口一").start();new Thread(tw, "售票口二").start();new Thread(tw, "售票口三").start();new Thread(tw, "售票口四").start();}}class TicketWindow implements Runnable {private int tickets = 10;public void run() {while (tickets > 0) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在发售第"+ tickets-- + "张票");}}}


测试结果:


在售票程序while循环中添加了sleep()方法,,这样也就是模拟了售票过程中,线程的延迟。

由于有延迟,当票号减为1时,假设线程1此时出售1号票,对票号进行判断之后,进入while循环,在售票之前通过sleep()方法让线程休眠,这时线程二会进行售票,由于此时此时票号仍为1,因此线程2也会进入循环,同理,四个线程都会进入循环,休眠结束后,四个线程都会卖票,这样就相当于将票号减了四次,结果中也就出现了0、-1、-2这样的现象


所以为了线程的安全问题,我们引入同步代码块以及同步方法


同步代码块

synchronized(lock){

        操作共享资源代码块

}

利用java的同步机制,可以保证在多个线程使用同一个资源时,用于处理共享资源的代码任何时候都只有一个线程进行访问

优化后的代码:

/** * 模拟窗口售票 * @author Shawn·Zhang */public class Example01 {public static void main(String[] args) {TicketWindow tw = new TicketWindow();new Thread(tw,"售票口一").start();new Thread(tw,"售票口二").start();new Thread(tw,"售票口三").start();new Thread(tw,"售票口四").start();}}class TicketWindow implements Runnable {private int tickets = 10;Object lock = new Object();@Overridepublic void run() {while (true) {synchronized (lock) {try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}if(tickets>0){System.out.println(Thread.currentThread().getName() + "正在发售第"+ tickets-- + "张票");}else{break;}}}}}
测试结果:

从测试结果可以看出,没有出现不正确的票。这是因为售票的代码实现了同步,之前出现的线程安全问题得以解决。


同步方法

与同步代码块同理,作用相同,只是书写格式有区别,在这里也写出来,以供学习

synchronized  返回值类型  方法名(){}

以售票案例为例,将上述的代码修改后,如下:

/** * 模拟窗口售票 * @author Shawn·Zhang */public class Example01 {public static void main(String[] args) {TicketWindow tw = new TicketWindow();new Thread(tw,"售票口一").start();new Thread(tw,"售票口二").start();new Thread(tw,"售票口三").start();new Thread(tw,"售票口四").start();}}class TicketWindow implements Runnable {private int tickets = 10;@Overridepublic void run() {while (true) {saleTickets();//调用售票方法if(tickets<=0){break;}}}private synchronized void saleTickets(){if(tickets>0){try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "正在发售第"+ tickets-- + "张票");}}}

结果可以参考同步代码块的测试结果。


死锁

在同步问题上,需要注意死锁问题,就是两个线程在运行的过程中,都在等待对方的锁,这样就会使得程序停滞

在开发中,要避免死锁的情况

public class Example06 {public static void main(String[] args) {Thread t1 = new Thread(new DeadLock(true));Thread t2 = new Thread(new DeadLock(false));t1.start();t2.start();}}class DeadLock implements Runnable{private boolean flag;//定义boolean类型的变量flagstatic Object locka = new Object();//定义锁对象lockastatic Object lockb = new Object();//定义锁对象lockbpublic DeadLock(boolean flag) {//有参构造方法this.flag = flag;}@Overridepublic void run() {if(flag){while(true){synchronized(locka){//锁对象上的同步代码块System.out.println("if locka");synchronized (lockb) {//锁对象上的同步代码块System.out.println("if lockb");}}}}else{while(true){synchronized(lockb){//锁对象上的同步代码块System.out.println("else lockb");synchronized (locka) {//锁对象上的同步代码块System.out.println("else locka");}}}}}}
测试结果会出现死锁现象

0 0
原创粉丝点击