
1、线程同步
并发:同一个对象多个线程同步操作

1 package cn.Thread_demo;
2
3 /**
4 * @Classname SynBlockTest01
5 * @Description TODO
6 * @Date 2019-5-13 12:16
7 * @Created by Administrator
8 */
9 public class SynBlockTest01 {
10 public static void main(String[] args) {
11 //一份资源
12 SynWeb12306 web = new SynWeb12306();
13 //多个代理
14 new Thread(web, "张三").start();
15 new Thread(web, "张四").start();
16 new Thread(web, "张五").start();
17 }
18 }
19
20 class SynWeb12306 implements Runnable {
21 //票数
22 private int ticketNums = 10;
23 private boolean flag = true;
24
25 @Override
26 public void run() {
27 while (flag) {
28 try {
29 Thread.sleep(100);
30 } catch (InterruptedException e) {
31 e.printStackTrace();
32 }
33 test2();
34 }
35 }
36 public synchronized void test2(){
37 synchronized (this){
38 if (ticketNums <= 0) {
39 flag = false;
40 return;
41 }
42 }
43 //模拟延时
44 try {
45 Thread.sleep(100);
46 } catch (InterruptedException e) {
47 e.printStackTrace();
48 }
49 System.out.println(Thread.currentThread().getName()+"--"+ticketNums--);
50 }
51
52 //线程不安全, tickNums对象在变
53 public synchronized void test(){
54 if (ticketNums <= 0) {
55 flag = false;
56 return;
57 }
58 //模拟延时
59 try {
60 Thread.sleep(200);
61 } catch (InterruptedException e) {
62 e.printStackTrace();
63 }
64 System.out.println(Thread.currentThread().getName()+"--"+ticketNums--);
65 }
66 }
运行图

2、影院购票模拟
-----简单版

1 package cn.Thread_demo;
2
3 import javax.security.auth.login.AccountException;
4
5 /**
6 * @Classname HappyCinema
7 * @Description TODO
8 * @Date 2019-5-14 10:30
9 * @Created by Administrator
10 * <p>
11 * #####选位置
12 */
13 public class HappyCinema {
14 public static void main(String[] args) {
15 Cinema c = new Cinema(2, "后天");
16 new Thread(new Customer(c,4),"张三").start();
17 new Thread(new Customer(c,2),"李四").start();
18 }
19 }
20
21 //顾客
22 class Customer implements Runnable {
23 Cinema cinema;
24 int seats;
25
26 public Customer(Cinema cinema, int seats) {
27 this.cinema = cinema;
28 this.seats = seats;
29 }
30
31 @Override
32 public void run() {
33 synchronized (cinema) {
34 boolean flag = cinema.bookTickets(seats);
35 if (flag) {
36 System.out.println("出票成功" + Thread.currentThread().getName() + "位置为:" + seats);
37 } else {
38 System.out.println("出票失败" + Thread.currentThread().getName() + "位置为不够");
39 }
40 }
41 }
42 }
43
44 //影院
45 class Cinema {
46 int available; //可供选择的位置
47 String name; //名称
48
49 public Cinema(int available, String name) {
50 this.available = available;
51 this.name = name;
52 }
53
54 //购票
55 public boolean bookTickets(int seats) {
56 System.out.println("可用位置为:" + available);
57 if (seats > available) {
58 return false;
59 }
60 available -= seats;
61 return true;
62 }
63 }
-----加入容器版

1 package cn.Thread_demo;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 /**
7 * @Classname HappyCinema
8 * @Description TODO
9 * @Date 2019-5-14 10:30
10 * @Created by Administrator
11 * <p>
12 * #####选位置
13 */
14 public class HappyCinema01 {
15 public static void main(String[] args) {
16 //可用位置
17 List<Integer> available = new ArrayList<>();
18 available.add(1);
19 available.add(2);
20 available.add(4);
21 available.add(5);
22 available.add(7);
23
24 //顾客需要的位置
25 List<Integer> seats1 = new ArrayList<>();
26 seats1.add(1);
27 seats1.add(2);
28 List<Integer> seats2 = new ArrayList<>();
29 seats2.add(3);
30 seats2.add(7);
31 HtCinema c = new HtCinema(available,"HtCinema");
32 new Thread(new HappyCustomer(c, seats1), "张三").start();
33 new Thread(new HappyCustomer(c, seats2), "李四").start();
34 }
35 }
36
37 //顾客
38 class HappyCustomer implements Runnable {
39 HtCinema cinema;
40 List<Integer> seats;
41
42 public HappyCustomer(HtCinema cinema, List<Integer> seats) {
43 this.cinema = cinema;
44 this.seats = seats;
45 }
46
47 @Override
48 public void run() {
49 synchronized (cinema) {
50 boolean flag = cinema.bookTickets(seats);
51 if (flag) {
52 System.out.println("出票成功" + Thread.currentThread().getName() + "位置为:" + seats);
53 } else {
54 System.out.println("出票失败" + Thread.currentThread().getName() + "位置为不够");
55 }
56 }
57 }
58 }
59
60 //影院
61 class HtCinema {
62 List<Integer> available; //可供选择的位置
63 String name; //名称
64
65 public HtCinema(List<Integer> available, String name) {
66 this.available = available;
67 this.name = name;
68 }
69
70 //购票
71 public boolean bookTickets(List<Integer> seats) {
72 System.out.println("可用位置为:" + available);
73 List<Integer> copy = new ArrayList<>();
74 copy.addAll(available);
75
76 //相减
77 copy.retainAll(seats);
78 //判断大小
79 if (available.size()-copy.size()!=seats.size()){
80 return false;
81 }
82 //成功
83 available = copy;
84 return true;
85 }
86 }
3、死锁
过多的同步可能造成相互不释放资源。从而相互等待,一般发生于同步中持有多个对象的锁。
4、线程协作
并发协作模型:“生产者/消费者模式”---管程法、信号灯法
生产者:负责生产数据的模块(这里的模块可能是:方法、对象、线程、进程)
消费者:负责处理数据的模块(这里的模块可能是:方法、对象、线程、进程)
缓冲区:消费者不能直接使用生产者的数据,他们之间有个“缓冲区”;生产者将生产好的数据放入“缓冲区”,消费者从“缓冲区”拿要处理的数据。

1 package cn.Thread_demo;
2
3 /**
4 * @Classname CoTest01
5 * @Description TODO
6 * @Date 2019-5-15 14:16
7 * @Created by Administrator
8 * 协作模型:生产者消费者实现方式一:管程法
9 */
10 public class CoTest01 {
11 public static void main(String[] args) {
12 SynContainer container = new SynContainer();
13 new Productor(container).start();
14 new Consumer(container).start();
15 }
16 }
17
18 //生产者
19 class Productor extends Thread {
20 SynContainer container;
21
22 public Productor(SynContainer container) {
23 this.container = container;
24 }
25
26 @Override
27 public void run() {
28 // 生产
29 for (int i = 0; i < 100; i++) {
30 System.out.println("生产--" + i + "个");
31 container.push(new Steamedbun(i));
32 }
33 }
34 }
35
36 //消费者
37 class Consumer extends Thread {
38 SynContainer container;
39
40 public Consumer(SynContainer container) {
41 this.container = container;
42 }
43
44 @Override
45 public void run() {
46 // 消费
47 for (int i = 0; i < 100; i++) {
48 System.out.println("消费--" + container.pop().id + "个");
49 container.push(new Steamedbun(i));
50 }
51 }
52 }
53
54 //缓冲区
55 class SynContainer {
56 Steamedbun[] buns = new Steamedbun[10]; //存储容器
57 int count = 0; //计数器
58
59 // 存储 / 生产
60 public synchronized void push(Steamedbun bun) {
61 // 何时能生产--- 容器存在空间
62 // 不能生产---等待
63 if (count==buns.length){
64 try {
65 this.wait(); //线程阻塞,消费者通知生产解除
66 } catch (InterruptedException e) {
67 e.printStackTrace();
68 }
69 }
70 // 存在空间--- 可以生产
71 buns[count] = bun;
72 count++;
73 this.notifyAll();
74 }
75
76 // 获取 / 消费
77 public synchronized Steamedbun pop() {
78 // 何时消费,容器中是否存在数据
79 // 没有数据---等待
80 if (count==0){
81 try {
82 this.wait(); //线程阻塞。生产者通知消费时解除
83 } catch (InterruptedException e) {
84 e.printStackTrace();
85 }
86 }
87 // 存在数据---可以消费
88 count--;
89 Steamedbun bun = buns[count];
90 this.notifyAll();
91 return bun;
92 }
93 }
94
95 //数据
96 class Steamedbun {
97 int id;
98
99 public Steamedbun(int id) {
100 this.id = id;
101 }
102 }

1 package cn.Thread_demo;
2
3 /**
4 * @Classname CoTest02
5 * @Description TODO
6 * @Date 2019-5-15 14:48
7 * @Created by Administrator
8 * 协作模型:生产者消费者实现方式一:信号灯法
9 * 借助标志位
10 */
11 public class CoTest02 {
12 public static void main(String[] args) {
13 Tv tv = new Tv();
14 new Player(tv).start();
15 new Watch(tv).start();
16 }
17 }
18
19 //生产者--演员
20 class Player extends Thread {
21 Tv tv;
22
23 public Player(Tv tv) {
24 this.tv = tv;
25 }
26
27 @Override
28 public void run() {
29 for (int i = 0; i < 20; i++) {
30 if (i % 2 == 0) {
31 this.tv.play("奇葩说");
32 } else {
33 this.tv.play("hello world");
34 }
35 }
36 }
37 }
38
39 //消费者--观众
40 class Watch extends Thread {
41 Tv tv;
42
43 public Watch(Tv tv) {
44 this.tv = tv;
45 }
46
47 @Override
48 public void run() {
49 for (int i = 0; i < 20; i++) {
50 tv.watch();
51 }
52 }
53 }
54
55 //同一个资源--电视
56 class Tv {
57 String voice;
58 //信号灯
59 //T 表示演员表演 观众等待
60 //F 表示观众观看 演员等待
61 boolean flag = true;
62
63 //表演
64 public synchronized void play(String voice) {
65 //演员等待
66 if (!flag) {
67 try {
68 this.wait();
69 } catch (InterruptedException e) {
70 e.printStackTrace();
71 }
72 }
73 System.out.println("表演了" + voice);
74 this.voice = voice;
75 //唤醒
76 this.notifyAll();
77 this.flag = !this.flag; //切换标志
78 }
79
80 //观看
81 public synchronized void watch() {
82 //观众等待
83 if (flag) {
84 try {
85 this.wait();
86 } catch (InterruptedException e) {
87 e.printStackTrace();
88 }
89 }
90 //观看
91 System.out.println("听到了" + voice);
92 //唤醒
93 this.notifyAll();
94 this.flag = !this.flag; //切换标志
95 }
96 }
5、单例模式

1 package cn.Thread_demo;
2
3 /**
4 * @Classname DoubleCheckedLocking
5 * @Description TODO
6 * @Date 2019-5-16 10:36
7 * @Created by Administrator
8 * ---单例模式:套路,在多线程环境下,对外存在一个对象
9 * 1、构造器私有化--避免外部new构造器
10 * 2、提供私有的静态属性--存储对象的地址
11 * 3、提供公共的静态方法--获取属性
12 */
13 public class DoubleCheckedLocking {
14 // 1、构造器私有化
15 private DoubleCheckedLocking() {
16
17 }
18
19 // 2、提供私有的静态属性(没有volatile,其他线程可能访问一个没有初始化的对象)
20 private static volatile DoubleCheckedLocking instance;
21
22 // 3、提供公共的静态方法
23 public static DoubleCheckedLocking getInstance() {
24 //再次检测
25 if (null != instance) { //避免不必要的同步,已经存在对象
26 return instance;
27 }
28 synchronized (DoubleCheckedLocking.class) {
29 if (null == instance) {
30 instance = new DoubleCheckedLocking();
31 }
32 return instance;
33 }
34 }
35
36 public static void main(String[] args) {
37 Thread t = new Thread(() -> {
38 System.out.println(DoubleCheckedLocking.getInstance());
39 });
40 t.start();
41 System.out.println(DoubleCheckedLocking.getInstance());
42 }
43 }
运行图

6、ThreadLocal
每个线程存储自己的数据,更改不会影响其他线程

1 package cn.Thread_demo;
2
3 /**
4 * @Classname ThreadLocalTest01
5 * @Description TODO
6 * @Date 2019-5-16 14:17
7 * @Created by Administrator
8 * ---ThreadLocal:每个线程自身的存储区域(本地、局部)
9 * get/set/initialValue
10 */
11 public class ThreadLocalTest01 {
12 // private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
13 // 更改初始化值
14 private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(()->200);
15 public static void main(String[] args) {
16 //获取值
17 System.out.println(Thread.currentThread().getName() + "-->" + threadLocal.get());
18 //设置值
19 threadLocal.set(199);
20 System.out.println(Thread.currentThread().getName() + "-->" + threadLocal.get());
21 new Thread(new MyRun()).start();
22 }
23 public static class MyRun implements Runnable{
24 @Override
25 public void run() {
26 threadLocal.set((int)(Math.random()*99));
27 System.out.println(Thread.currentThread().getName() + "-->" + threadLocal.get());
28 }
29 }
30 }
运行图

7、可重入锁:锁可以延续使用

1 package cn.Thread_demo;
2
3 /**
4 * @Classname LockTest
5 * @Description TODO
6 * @Date 2019-5-16 15:14
7 * @Created by Administrator
8 * 可重入锁:锁可以延续使用
9 */
10 public class LockTest {
11 public void test(){
12 //第一次获得锁
13 synchronized (this){
14 while (true){
15 //第二次获得同样的锁
16 synchronized (this){
17 System.out.println("ReentrantLock!");
18 }
19 try {
20 Thread.sleep(1000);
21 } catch (InterruptedException e) {
22 e.printStackTrace();
23 }
24 }
25 }
26 }
27
28 public static void main(String[] args) {
29 new LockTest().test();
30 }
31 }
运行图

8、JUC
来源:https://www.cnblogs.com/Anemia-BOY/p/10857710.html
