java多进程 -CD7-孙鑫-(4)-同步方法,同步块,售票例子

来源:互联网 发布:小提琴 曲 知乎 编辑:程序博客网 时间:2024/05/29 03:30

本节主要包含使用内部类来实现与使用Runnable接口实现线程一样的效果,还包含一个小例子售票来引出同步机制:同步块和同步方法

使用实现Runnable方法好处有两条:

  1. 如果你的MyThread类已经继承了一个类,那么java中不允许多继承,这样让你的MyThread实现一个Runnable接口正好啊。
  2. 如果同一个对象创建多线程那么共享一个数据成员index

使用内部类同样可以实现使用Runnable的两条好处

class MultiThread{    public static void main(String[] args)    {        MyThread myThread = new MyThread();        //如果创建多个线程但是是同一个对象,那么他们共享一个index        //new Thread(myThread).start();        //new Thread(myThread).start();        //new Thread(myThread).start();        //new Thread(myThread).start();        //new Thread(myThread).start();        myThread.getThread().start();        myThread.getThread().start();        myThread.getThread().start();        myThread.getThread().start();        //设置为后台线程        //myThread.setDaemon(true);        //设置优先级        //myThread.setPriority(Thread.MAX_PRIORITY);        //myThread.start();        //int index = 1;        while(true)        {                //if(index++ == 1000)                //break;                //获取当前的线程并且获取它的名字            System.out.println("main方法所在的线程的名字:" + Thread.currentThread().getName());           }    }}class MyThread //implements Runnable//extends Thread{    int index = 0;    class InnerThread extends Thread    {           public void run()        {            while(true)            {            //内部类可以访问外部类的成员            System.out.println(Thread.currentThread().getName() + ":" + index++);               //将当前线程暂停            //yield();            }           }    }     //隐藏实现细节    Thread getThread()    {        return new InnerThread();    }    //run方法是线程的入口函数    /*public void run()    {        while(true)        {            System.out.println(Thread.currentThread().getName() + ":" + index++);               //将当前线程暂停            //yield();        }       }*/ }

联系模拟火车票售票系统
public static void sleep (long millis, int nanos)
线程的同步
The code segments within a program that access the same object from separate, concurrent threads are called “critical sections”。
在一个程序当中代码段访问了同一个对象从单独的并发的线程当中,那么这个代码段叫”临界区”
使用同步的机制对临界区进行保护

同步的两种方式:同步块和同步方法
对于同步来说都是使用synchronized方法

每一个对象都有一个监视器,或者叫做锁。
同步块示例

//C:\Users\Administrator\Documents\GitHubpackage ticket;class Tickets {    public static void main(String[] args)    {        sellTickets st = new sellTickets();        //四个线程同时卖这100张票,注意是同一个对象创建四个线程,他们共享同一个变量ticket        new Thread(st).start();        new Thread(st).start();        new Thread(st).start();        new Thread(st).start();    }}class sellTickets implements Runnable{    int ticket = 100;    Object o = new Object();    @Override    public void run() {        while(true)        {            //每一个对象都有一个监视器,或者叫做锁。同步块示例            synchronized (o) {                if(ticket > 0)                {                    //存在的隐藏的问题当ticket=1,它的时间片到期了进入到if语句中,第二个线程进入到if语句然后时间片到期                    try {                        //线程睡眠,该方法需要写异常                        Thread.sleep(10);                    } catch (InterruptedException e) {                        e.printStackTrace();                                        }                    //第几个线程卖出了第多少张票                    System.out.println(Thread.currentThread().getName() + "sell tickets" + ticket);                    ticket--;                }            }        }    }}

同步方法示例

//C:\Users\Administrator\Documents\GitHubpackage ticket;class Tickets {    public static void main(String[] args)    {        sellTickets st = new sellTickets();        //四个线程同时卖这100张票,注意是同一个对象创建四个线程,他们共享同一个变量ticket        new Thread(st).start();        new Thread(st).start();        new Thread(st).start();        new Thread(st).start();    }}class sellTickets implements Runnable{    int ticket = 100;    Object o = new Object();    @Override    public void run() {        while(true)        {            sell();        }    }    public synchronized void sell()    {        if(ticket > 0)        {            //存在的隐藏的问题当ticket=1,它的时间片到期了进入到if语句中,第二个线程进入到if语句然后时间片到期            try {                //线程睡眠,该方法需要写异常                Thread.sleep(10);            } catch (InterruptedException e) {                e.printStackTrace();                                }            //第几个线程卖出了第多少张票            System.out.println(Thread.currentThread().getName() + "sell tickets" + ticket);            ticket--;        }    }}

同步方法利用的是this所代表的对象加的锁。

示例:分别使用同步块和同步方法来实现正确的结果
当同步块利用this所代表的对象synchronized (this)时就和同步方法使用的锁一致了

//C:\Users\Administrator\Documents\GitHubpackage ticket;class Tickets {    public static void main(String[] args) {        sellTickets st = new sellTickets();        // 四个线程同时卖这100张票,注意是同一个对象创建四个线程,他们共享同一个变量ticket        new Thread(st).start();        //为什么写sleep因为当我们main时间片没有消耗完,不会执行new Thread(st).start()(第一个)那么st.b = true;赋值执行了并且赋值成功,当main 时间片消耗完再来执行new Thread(st).start()(第一个),此时已经是为false了,所以写sleep 是为了让主线程睡一会        try{            Thread.sleep(1);        }catch(Exception e){            e.printStackTrace();        }        st.b = true;        new Thread(st).start();    }}class sellTickets implements Runnable {    int ticket = 100;    Object o = new Object();    //定义一个boolean变量让同步块和同步方法分别执行    public boolean b = false;    @Override    public void run() {            if (b == false) {                while (ticket > 0) {                    try {                        // 线程睡眠,该方法需要写异常                        Thread.sleep(10);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    //false时执行同步方法                    sell();                }            } else {                //当true时执行同步块                while (ticket > 0) {                    try {                        // 线程睡眠,该方法需要写异常                        Thread.sleep(10);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                    synchronized (this) {                        if(ticket > 0){                            // 第几个线程卖出了第多少张票                            System.out.println("obj"                                    + Thread.currentThread().getName()                                    + "sell tickets" + ticket);                            ticket--;                        }                    }                }            }        }    public synchronized void sell() {        if(ticket > 0){            // 第几个线程卖出了第多少票号的张票            System.out.println("sell:" + Thread.currentThread().getName()                    + "sell tickets" + ticket);            ticket--;        }    }}

结果:
sell:Thread-0sell tickets10
objThread-1sell tickets9
sell:Thread-0sell tickets8
objThread-1sell tickets7
sell:Thread-0sell tickets6
objThread-1sell tickets5
sell:Thread-0sell tickets4
objThread-1sell tickets3
sell:Thread-0sell tickets2
objThread-1sell tickets1
下节预告
每个class也有一个锁,是这个class所对应的Class对象的锁。

0 0
原创粉丝点击