java学习多线程之卖票示例

这一节我们来说一个示例就是卖票示例:

需求:

我们现在有100张票,然后分四个窗口来卖,直到卖完为止。

思路:

1、先定一个一个票类,描述票的属性,还有打印卖出的票,并且实现Runnable中的run方法。

2、定义一个主方法,把这个类当成一个独立的运行程序。

3、在主方法当中创建4个线程来卖票。

代码:

 1 class Ticket implements Runnable
 2 {
 3 
 4     int num = 100;
 5 
 6     public void sellT()
 7     {
 8 
 9         while(true)
10         {
11 
12             if(num>0)
13                 System.out.println(num--);
14 
15         }
16 
17     }
18 
19     public void run()
20     {
21 
22         sellT();
23 
24     }
25 
26 }
27 
28 class ThreadTickets
29 {
30 
31     public static void main(String[] args) {
32         
33         Ticket p = new Ticket();
34 
35         Thread t1 = new Thread(p);
36         Thread t2 = new Thread(p);
37         Thread t3 = new Thread(p);
38 
39         t1.start();
40         t2.start();
41         t3.start();
42 
43     }
44 
45 }

我们写完之后,在不是很慢的电脑上运行都是正常的,但是我们的这个程序总体上安全么?如果在if(num>0)这个地方线程一刚要执行的时候被切换出去了那么num此时如果恰巧是1的话,那么此时线程二进来后1>0之后就直接打印1,但是在线程一苏醒之后,这时候他不再判断num是否大于零而是直接打印了 num--这个时候就出现了0甚至是负数。这就是多线程当中出现的问题,那么如何解决这个问题。我们可以试想一下,如果在线程一退出的时候,能够让num不让其他对象访问,直到线程一苏醒之后处理完num之后,再让出num的控制权的话,这样是不是很安全呢,这个也叫做多线程当中的同步。同步是指,在同时有多个线程运行的时候,其中有一段代码块一个时候只能允许一个线程来处理,只有这个线程处理完了之后,其他的线程才有机会重新掌管这个代码块,周而复始。

java为了能够让我们处理上述的不同步问题就是一个线程执行的同时,其中共享的资源分别被其他的线程来执行着,这样就可能造成输出了不该输出的语句。为我们提供了一个关键字叫做synchronized。这个关键词的使用方法,是指定一个锁,来访问其内部的代码块。如果一个线程要处理访问其中的代码块的话,必须先拿到锁。并且这个锁要是所有的线程公用的锁才好,这样才能够起到锁的作用。当一个线程拿到锁之后,其他线程来访问的话如果没有锁,则一直判断另一个线程的锁是否释放,只有持有锁的线程把任务执行完之后,才会释放锁。这个锁一释放之后,其他的线程就有机会持有这个锁,然后进行任务的操作。这样就在多线程的情况下,保证了在某一个时刻,只能由一个线程来执行这段同步代码块。也保证了共享数据的安全性,不至于这段数据在被修改之后,其他线程仍然认为这个数据就是之前的按个数据的问题。究竟如何使用呢,代码如下:

 1 class Ticket implements Runnable
 2 {
 3 
 4     int num = 100;
 5 
 6     Object obj = new Object();
 7 
 8     public void sellT()
 9     {
10 
11         while(true)
12         {
13             synchronized (obj)
14             {
15 
16                 if(num>0)
17                 {
18                     try
19                     {
20 
21                         Thread.sleep(10);
22 
23                     }catch(InterruptedException e)
24                     {
25 
26 
27                     }
28                     System.out.println("The CurrentThread is:"+Thread.currentThread().getName()+"The num is:"+num--);
29 
30                 }        
31 
32             }
33         }
34 
35     }
36 
37     public void run()
38     {
39 
40         sellT();
41 
42     }
43 
44 }
45 
46 class ThreadTickets
47 {
48 
49     public static void main(String[] args) {
50         
51         Ticket p = new Ticket();
52 
53         Thread t1 = new Thread(p);
54         Thread t2 = new Thread(p);
55         Thread t3 = new Thread(p);
56 
57         t1.start();
58         t2.start();
59         t3.start();
60 
61     }
62 
63 }

其中同步代码块还有一种简写的形式,也就是说把代码块关键字synchronized( lock ){},把synchronized直接放到函数上,这样整个函数就是同步的了。也就是:

 1 class Ticket implements Runnable
 2 {
 3 
 4     int num = 100;
 5 
 6     Object obj = new Object();
 7 
 8     public void sellT()
 9     {
10 
11         while(true)
12         {
13             try
14             {
15 
16             Thread.sleep(100);
17 
18             }catch(InterruptedException e)
19             {
20 
21 
22             }
23             pTicket();        
24             
25         }
26 
27     }
28 
29     public synchronized  void pTicket()
30     {
31 
32         if(num>0)
33         {
34 
35             System.out.println("The CurrentThread is:"+Thread.currentThread().getName()+"The num is:"+num--);
36 
37         }
38 
39     }
40 
41     public void run()
42     {
43 
44         sellT();
45 
46     }
47 
48 }
49 
50 class ThreadTickets
51 {
52 
53     public static void main(String[] args) {
54         
55         Ticket p = new Ticket();
56 
57         Thread t1 = new Thread(p);
58         Thread t2 = new Thread(p);
59         Thread t3 = new Thread(p);
60 
61         t1.start();
62         t2.start();
63         t3.start();
64 
65     }
66 
67 }

synchronized这个关键字加到代码块之前就是同步代码块,加到函数上面就是同步函数。

原文地址:https://www.cnblogs.com/sunchuanzhen/p/3379026.html