多线程解决同步问题浅析

一,问题背景

1.为什么要引入多线程?

     用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现。说这个话其实只有一半对,因为反应“多角色”的程序代码,最起码每个角色要给他一个线程吧,否则连实际场景都无法模拟,当然也没法说能用单线程来实现:比如最常见的“生产者,消费者模型”。

2.多线程、同步、并发概念:

多线程:指的是这个程序(一个进程)运行时产生了不止一个线程。
并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。

3.引入多线程后会带来那些问题?

      java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用,从而保证了该变量的唯一性和准确性。

以买票系统为例,我们发现不加控制多线程会出现超卖现象。

 1 public class RunnableImpl implements Runnable {
 2 
 3 private int ticket=100;
 4     @Override
 5     public void run() {
 6         while(true){
 7             if (ticket<=0){
 8                 break;
 9             }
10             try {
11                 Thread.sleep(200);
12                 String name = Thread.currentThread().getName();
13                 System.out.println("第"+name+"窗口正在卖出第"+(200-ticket+1)+"张票,剩余"+(--ticket)+"张");
14             } catch (InterruptedException e) {
15                 e.printStackTrace();
16             }
17 
18         }
19 
20 
21 
22     }
23 }

测试类:

1 public class originticket {
2     public static void main(String[] args) {
3         RunnableImpl runnable = new RunnableImpl();
4        new Thread(runnable,"一").start();
5        new Thread(runnable,"二").start();
6     }
7 }

结果显示:

二,问题解决方案之synchronize代码块:

 1 public class RunnableImplsyn implements Runnable {
 2 
 3 private int ticket=200;
 4     @Override
 5     public void run() {
 6         while(true) {
 7             try {
 8                 Thread.sleep(200);
 9             } catch (InterruptedException e) {
10                 e.printStackTrace();
11             }
12             synchronized (this) {
13             if (ticket <= 0) {
14                 break;
15             }
16 
17 
18                     String name = Thread.currentThread().getName();
19                     System.out.println("第" + name + "窗口正在卖出第" + (200 - ticket + 1) + "张票,剩余" + (--ticket) + "张");
20 
21 
22             }
23         }
24 
25 
26     }
27 }

测试类:

1 public class synchronizeblockTicket {
2 
3     public static void main(String[] args) {
4         RunnableImplsyn runnableImplsyn = new RunnableImplsyn();
5         new Thread(runnableImplsyn,"一").start();
6         new Thread(runnableImplsyn,"二").start();
7     }
8 }

结果:

三,问题解决方案之synchronize方法:

这里抽取了方法,this代指:

 1 public class RunnableImplsynfn implements Runnable {
 2 
 3 private static int ticket=200;
 4     @Override
 5     public void run() {
 6        test();
 7    
 8     }
 9 
10 
11     private synchronized void test() {
12         while(true){
13             if (ticket<=0){
14                 break;
15             }
16             try {
17                 Thread.sleep(200);
18                 String name = Thread.currentThread().getName();
19                 System.out.println("第"+name+"窗口正在卖出第"+(200-ticket+1)+"张票,剩余"+(--ticket)+"张");
20             } catch (InterruptedException e) {
21                 e.printStackTrace();
22             }
23 
24         }
25 
26 
27 
28     }
29     }

测试类:

1 public class synchronizefnTicket {
2 
3 
4     public static void main(String[] args) {
5         RunnableImplsynfn runnableImplsyn = new RunnableImplsynfn();
6         new Thread(runnableImplsyn,"一").start();
7         new Thread(runnableImplsyn,"二").start();
8     }
9 }

四,问题解决方案之静态synchronize方法:

同上

 1 public class RunnableImplsynfn implements Runnable {
 2 
 3 private static int ticket=200;
 4     @Override
 5     public void run() {
 6         statictest();
 7 
 8     }
 9 
10     private static synchronized void statictest() {
11         while(true){
12             if (ticket<=0){
13                 break;
14             }
15             try {
16                 Thread.sleep(200);
17                 String name = Thread.currentThread().getName();
18                 System.out.println("第"+name+"窗口正在卖出第"+(200-ticket+1)+"张票,剩余"+(--ticket)+"张");
19             } catch (InterruptedException e) {
20                 e.printStackTrace();
21             }
22 
23         }
24 
25     }
26    
27 
28     }
29     }

测试类一样略。

五,问题解决方案之lock方法:

 1 import java.util.concurrent.locks.Lock;
 2 import java.util.concurrent.locks.ReentrantLock;
 3 
 4 public class Runnablelock implements Runnable {
 5     private int ticket=200;
 6    Lock l= new ReentrantLock();
 7 
 8     @Override
 9     public void run() {
10         while(true){
11  /*       try {
12         Thread.sleep(20);
13         } catch (InterruptedException e) {
14             e.printStackTrace();
15         }*/
16 l.lock();//从此以后加锁
17 
18             if (ticket<=0){
19                 break;
20             }
21             try {
22                 Thread.sleep(200);
23 
24                 String name = Thread.currentThread().getName();
25                 System.out.println("第"+name+"窗口正在卖出第"+(200-ticket+1)+"张票,剩余"+(--ticket)+"张");
26             } catch (InterruptedException e) {
27                 e.printStackTrace();
28             }finally {
29                 l.unlock();//释放锁
30             }
31 
32         }
33 
34 
35     }
36 }

测试类:

1 public class lockTicket {
2 
3 
4     public static void main(String[] args) {
5         Runnablelock runnablelock = new Runnablelock();
6         new Thread(runnablelock,"一").start();
7         new Thread(runnablelock,"二").start();
8     }
9 }
当一个男人不再对你啰嗦,不再缠着你,不再没事找你,对你说话也客气了,也不再气你了。那么恭喜你,你已经成功的失去了他。别嫌弃男人幼稚,那是他喜欢你,爱你。女人说男人像小孩子一样不成熟,可又有谁知道,男人在自己喜欢的女人面前才像小孩子,如果不喜欢你了,不爱你了,他比你爸还成熟。
原文地址:https://www.cnblogs.com/fengtangjiang/p/11103595.html