2017-03-31-多线程同步-关键字synchronized
Xplorist Lv6

2017-03-31-多线程同步-关键字synchronized

知识点1:

同步关键字:synchronized

在继承的多线程实现中也可以实现对一个类的同一个对象多次操作,只需要在这个继承线程的线程类中将一个类的对象设置为成员变量,再在run()方法中将这个类的方法执行行了,在主线程中创建操作同一个对象的多个线程子类就行了。

对方法加锁,一般不放在run()方法中。

知识点2:

等待和唤醒只能在锁里面使用

wait()某个对象调用时,使线程使方法或方法块的同步锁失效,使得其他的线程的也能够访问这个方法

notify()配合wait()使用,唤醒线程使线程同步锁恢复锁定,其他的线程就不能够进入到这个方法中了。

图文详解1:
2017-03-31-01.png
2017-03-31-02.png
2017-03-31-03.png
2017-03-31-04.png
2017-03-31-05.png
2017-03-31-06.png


窝窝头:
2017-03-31-07.png
2017-03-31-08.png
2017-03-31-09.png
2017-03-31-10.png
2017-03-31-11.png
2017-03-31-12.png
2017-03-31-13.png

实例1:

模拟线程死锁

密室逃脱

核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.share.demo03_31_多线程安全锁;

public class Game {
    public Object key1;
    public Object key2;

    public Game() {
        key1 = new Object();
        key2 = new Object();
    }

    public void start(int n) {
        if (n > 0) {
            System.out.println(Thread.currentThread().getName() + "进入游戏");
            synchronized (key1) {
                System.out.println(Thread.currentThread().getName() + "得到了key1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                synchronized (key2) {
                    System.out.println(Thread.currentThread().getName() + "得到了key2");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
            System.out.println(Thread.currentThread().getName() + "逃脱成功");

        } else {
            System.out.println(Thread.currentThread().getName() + "进入了游戏");
            synchronized (key2) {
                System.out.println(Thread.currentThread().getName() + "得到了key2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                synchronized (key1) {
                    System.out.println(Thread.currentThread().getName() + "得到了key1");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
            System.out.println(Thread.currentThread().getName() + "逃脱成功");
        }
    }

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.share.demo03_31_多线程安全锁;

public class GameThread extends Thread {
    public Game game;
    public int n;

    public GameThread(String name, Game game, int n) {
        super(name);
        this.game = game;
        this.n = n;
    }

    @Override
    public void run() {
        game.start(n);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.share.demo03_31_多线程安全锁;

public class GameStart {
    public static void main(String[] args) {
        Game game = new Game();

        GameThread gt1 = new GameThread("甲", game, -1);
        GameThread gt2 = new GameThread("乙", game, 1);

        gt1.start();
        gt2.start();
    }
}

实例2:

爱心便当问题,中午打饭: 1、食堂—-将饭菜打包【生产爱心便当】、取出爱心便当 2、最多存放三个爱心便当 3、有三个爱心人士做爱心便当 4、有6个人取便当

核心代码:

老师的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package com.share.test_3_31;

import java.util.Random;

public class Test {

    /*
     * 中午打饭: 1、食堂----将饭菜打包【生产爱心便当】、取出爱心便当 2、最多存放三个爱心便当 3、有三个爱心人士做爱心便当 4、有6个人取便当
     */
    public static void main(String[] args) {

        Test t = new Test();
        Mess mess = t.new Mess();
        People people1 = t.new People("1号工作人员",mess);
        People people2 = t.new People("2号工作人员",mess);
        People people3 = t.new People("3号工作人员",mess);
        Student s1 = t.new Student(mess,"汪洪毅");
        Student s2 = t.new Student(mess,"滕彩俊");
        Student s3 = t.new Student(mess,"林杰");
        Student s4 = t.new Student(mess,"谭小雨");
        Student s5 = t.new Student(mess,"肖峰");
        Student s6 = t.new Student(mess,"徐周");
        people1.start();
        people2.start();
        people3.start();
        s1.start();
        s2.start();
        s3.start();
        s4.start();
        s5.start();
        s6.start();
        //java程序里最多能同时跑多少个线程
    }

    /**
     * 爱心午餐
     */
    public class Lunch {
        String food[] = { "凉拌豆腐干", "烧黄豆", "回锅肉", "麻婆豆腐", "清炒白菜" };
        String first;// 第一个菜
        String second;// 第二个菜
        String third;// 第三个菜

        public Lunch() {
            // 初始化属性
            first = food[new Random().nextInt(food.length)];
            second = food[new Random().nextInt(food.length)];
            third = food[new Random().nextInt(food.length)];
        }

        public String toString() {
            return "【" + first + "+" + second + "+" + third + "】";
        }
    }

    /**
     * 食堂
     */
    public class Mess {
        Lunch box[] = new Lunch[3];
        int index = 0;

        public synchronized void put(Lunch wucan) {// 将制作好的爱心便当放到指定位置

            while (index == box.length) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            this.notify();
            box[index] = wucan;
            index++;
        }

        public synchronized Lunch get() {

            while (index == 0) {
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            this.notify();
            index--;
            return box[index];
        }// 从指定位置取爱心便当
    }

    /**
     * 食堂的工作人员 负责生产爱心便当
     */
    public class People extends Thread{

        public Mess mess = null;
        
        public People(String name,Mess mess){
            super(name);
            this.mess = mess;
        }
        
        @Override
        public void run() {
            while(true){
                Lunch lunch = new Lunch();
                mess.put(lunch);
                System.out.println(Thread.currentThread().getName()+"制作了爱心便当:"+lunch);
                try {
                    sleep(new Random().nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        
    }

    /**
     * 消费者
     */
    public class Student extends Thread{
        public Mess mess = null;
        
        public Student(Mess mess,String name){
            super(name);
            this.mess = mess;
        }
        
        @Override
        public void run() {
            Lunch lunch = mess.get();
            System.out.println(Thread.currentThread().getName()+"拿了一份爱心便当"+lunch);
        }
    }
}

实例3:

窝窝头问题

核心代码:

老师的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
public class ProducerConsumer {
    public static void main(String[] args) {
        SyncStack ss = new SyncStack();
        Producer p = new Producer(ss);
        Consumer c = new Consumer(ss);
        new Thread(p).start();
        new Thread(p).start();
        new Thread(p).start();
        new Thread(c).start();
    }
}

class WoTou { // 窝窝头
    int id; // 窝窝头id

    WoTou(int id) {
        this.id = id;
    }

    public String toString() {
        return "WoTou : " + id;
    }
}

class SyncStack {// 同步栈
    int index = 0;// 下标
    WoTou[] arrWT = new WoTou[6];// 窝窝头的数组..假设只能装6个窝窝头

    public synchronized void push(WoTou wt) {// 装窝窝头的筐子..放窝窝头
        System.out.println(index);
        while (index == arrWT.length) {
            try {
                this.wait(); // 如果筐子满了,就休息会。。。(等待)当前正在访问的线程wait-----this
                System.out.println(Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notifyAll(); // ....当前正在访问的线程唤醒notifyAll-----this
        arrWT[index] = wt;
        index++;
    }

    public synchronized WoTou pop() {// 拿窝窝头
        System.out.println(arrWT.length);
        while (index == 0) {
            try {
                this.wait(); // 如果拿完了筐子里的窝窝头。
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.notifyAll(); // 唤醒
        index--;
        return arrWT[index];
    }
}

class Producer implements Runnable {// 生产者,生产窝窝头............厨师
    SyncStack ss = null;

    Producer(SyncStack ss) {
        this.ss = ss;
    }

    public void run() {
        for (int i = 0; i < 20; i++) {
            WoTou wt = new WoTou(i);
            ss.push(wt);
            System.out.println("生产了:" + wt);
            try {
                Thread.sleep((int) (Math.random() * 200));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable {// 消费者..........消费窝窝头..........吃的人
    SyncStack ss = null;

    Consumer(SyncStack ss) {
        this.ss = ss;
    }

    public void run() {
        for (int i = 0; i < 20; i++) {
            WoTou wt = ss.pop();
            System.out.println("消费了: " + wt);
            try {
                Thread.sleep((int) (Math.random() * 1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
 评论