一,问题背景
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 }