Java多线程知识点整合 - 1

2018-12-05  本文已影响0人  Earl_iu

视频:https://www.bilibili.com/video/av33688545/?p=21
源码:[https://github.com/EduMoral/edu/tree/master/concurrent/src/yxxy]
书:Java并发编程实战+深入理解Java虚拟机
(https://github.com/EduMoral/edu/tree/master/concurrent/src/yxxy)

class Thread{
    private Runnable r;
    Thread(){
        
    }
    Thread(Runnable r){
    
    }
    public void run(){
        if(r!=null){
            r.run();
        }
    }
    public void start(){
        run();
    }

}
public void n(){
    synchronized(this){        // 自身为锁
        count--;
    }
}

Object o = new Object();
public void n(){
    synchronized(o){
        count--;
    }
}

public synchronized void m(){        // 此方法等同于synchronized(this)
    count--;
}

public synchronized static void m(){    // 当synchronizedy应用于静态方法时,等同于synchronized(T.class),以该类为锁
    count--;    
}
// 当我们set了一个值以后,我们在调用getBalance的时候,很有可能set方法还没有完成,所以读写方法都需要同步
// getBalance方法同步以后,在set方法没结束以前不可以进行getBalance方法

public synchronized void set(String name, double balance) {
        this.name = name;
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        this.balance = balance;
    }
    
    public synchronized double getBalance(String name) {
        return this.balance;   
    }

public static void main(String[] args) {
        Account a = new Account();
        new Thread(()->a.set("zhangsan", 100.0)).start();
        
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println(a.getBalance("zhangsan"));
        
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        System.out.println(a.getBalance("zhangsan"));
    }
synchronized void m1(){            // 当一个线程调用了m1以后,获得了this这把锁,但是m1调用了m2时,又需要申请获得相同的this锁,这种操作是可行的,因为在同一个线程以内
    m2;
}

synchronized void m2(){
    System.out.println();
}
public class inherit {
    public static void main(String[] args) {
       Son s = new Son();
       s.doSomething();
    }
    
}

class Father{
    public synchronized void doSomething(){
        System.out.println(this.getClass());
    }
}

class Son extends Father{
    public synchronized void doSomething(){
        super.doSomething();            // 通过super引用调用从父类继承来的doSomething()方法,那么锁还是当前子类对象,super等同于(Father)this,本质上还是this对象
        System.out.println(this.getClass());
    }
}

output:
class multi.thread.Son
class multi.thread.Son
public void a(){
    synchronized(lock_A){
        b();
    }
}

public void b(){
    synchronized(lock_B){
        a();
    }
}
java工作的内存模型 volatile为什么没有原子性
public class volatile_test implements Runnable{
    volatile boolean running = true;
    void m(){
        System.out.println("start");
        while(running){
            
        }
        System.out.println("end");
    }
    public void run() {
                this.m();
    }
    public static void main(String[] args) {
        volatile_test t = new volatile_test();
        Thread th = new Thread(t);
        th.start();
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t.running = false;   // 当没有volatile关键字的时候,running值的改变,线程并不会知道
    }
    
}
if(count.get()<100){
    count.incrementAndGet();        // 当count=999时,调用count.get()<1000,返回true以后,新的线程进入,将count+1,再调用count.incrementAndGet时,count已经等于1000了,结果会变成1001
}
String s1 = "Hello";
String s2 = "Hello";
// 尽管引用不同,但是都指向了同一个String对象"Hello"
方法1:
// 让count参数变成volatile的,这样数据变化时会通知别的线程

public class count_control {
    private ArrayList a = new ArrayList();
    volatile int count = 0;
    public void add(Object o){
        a.add(o);
    }
    public int get(){
        count = a.size();
        return count;
    }
    public static void main(String[] args) {
        count_control c = new count_control();
        Thread t1 = new Thread(()->{
            for(int i =0;i<10;i++){
                c.add(new Object());
                System.out.println(i);
            }
        });
        t1.start();
        
        new Thread(()->{
            while(true){
                if(c.get() ==5){            // 这里为Class t2的简写
                    break;
                }
            }
            System.out.println("get 5");
        });
        
        t2 t3 = new t2(c);
        t3.start();
    }
}


class t2 extends Thread{
    private count_control c;
    t2(count_control c){
        this.c = c;
    }
    public void run(){
        while(true){
            if(c.get() == 5){
                break;
            }
        }
        System.out.println("get2");
    }
}
方法2:   while循环的监控浪费cpu
使用wait和notify做到,wait会释放锁,而notify不会释放锁

public class count_cc2 {
    private ArrayList a = new ArrayList();
    int count = 0;
    public void add(Object o){
        a.add(o);
    }
    public int get(){
        count = a.size();
        return count;
    }
    
    public static void main(String[] args) {
        final Object lock = new Object();
        count_cc2 c2 = new count_cc2();
        new Thread(()->{
           synchronized(lock){
               System.out.println("t2启动");
               if(c2.get() != 5){
                   try {
                       lock.wait();
                   } catch (InterruptedException ex) {
                       Logger.getLogger(count_cc2.class.getName()).log(Level.SEVERE, null, ex);
                   }
               }
               System.out.println("t2关闭");
               lock.notify();
           } 
        }).start();
        
        new Thread(()->{
            System.out.println("t1启动");
            synchronized(lock){
                for(int i =0;i<10;i++){
                    c2.add(new Object());
                    System.out.println(i);
                    if(i ==5){
                        lock.notify();
                        try {
                            lock.wait();
                        } catch (InterruptedException ex) {
                            Logger.getLogger(count_cc2.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    } 
                }
            }
        },"t1").start();
    }
    
}

方法3: 使用Latch 门闩代替wait notify
当不涉及同步,只涉及线程通信的时候,用synchronized和wait/notify显得太重

public class count_cc3 {

    private ArrayList a = new ArrayList();
    int count = 0;
    public void add(Object o){
        a.add(o);
    }
    public int get(){
        count = a.size();
        return count;
    }
    
    public static void main(String[] args) {
        count_cc2 c2 = new count_cc2();
        CountDownLatch cdl = new CountDownLatch(1);
        new Thread(()->{
               System.out.println("t2启动");
               if(c2.get() != 5){
                   try {
                       cdl.await();            // 不为5的时候把latch关上,线程停止
                   } catch (InterruptedException ex) {
                       Logger.getLogger(count_cc3.class.getName()).log(Level.SEVERE, null, ex);
                   }
               }
               System.out.println("t2关闭");
        }).start();
        
        new Thread(()->{
            System.out.println("t1启动");
                for(int i =0;i<10;i++){
                    c2.add(new Object());
                    System.out.println(i);
                    if(c2.get() ==5){
                        cdl.countDown();            // 当为5的时候,我们把latch打开,线程1重新开启
                    }
                }
        }).start();
    }
    
}
面试题:写一个固定容量同步容器,拥有put和get方法,以及getCount方法,
能够支持2个生产者线程以及10个消费者线程的阻塞调用   
使用wait和notify/notifyAll来实现

public class container<T> {
    private LinkedList<T> link = new LinkedList<>();
    private int Max = 10;    // 最多10个元素
    private int count = 0;

    public synchronized T get(){
        T t = null;
        while(link.size() == 0){
            try{
                this.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
        t = link.removeFirst();
        count--;
        this.notifyAll();
        return t;
    }

    public synchronized void put(T t){
        while(link.size() == Max){                // 在使用wait()的时候,大部分时间都是while而不是if,因为if判断时,wait结束以后会直接向下                                                             进行,而不会再判断一次,如果这时候size又满了,就会出现异常
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        link.add(t);
        count++;
        this.notifyAll();          //通知消费者进行消费
    }

    public static void main(String args[]){
        container<String> c = new container();
        for(int i = 0;i<10;i++){
            new Thread(()->System.out.println("获取:"+c.get())).start();
        }

        for(int i=0;i<2;i++){
            new Thread(()->{
                for(int j=0;j<25;j++){
                    c.put("11");
                }
            }).start();
        }
    }
}
上一篇 下一篇

猜你喜欢

热点阅读