代码理解多线程(二)

volatile 到底有什么用?

package test19218;

import java.util.ArrayList;
import java.util.List;

public class ListAdd1 {

    
    
    //变量
    private  static List list = new ArrayList();    
    
    
    //变量变化
    public void add(){
        list.add("bjsxt");
    }
    public int size(){
        return list.size();
    }
    
    public static void main(String[] args) {
        
        
        //实列化一个对象
        final ListAdd1 list1 = new ListAdd1();
        
        
        //进行变量的变化
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for(int i = 0; i <10; i++){
                        list1.add();
                        System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");
                        Thread.sleep(500);
                    }    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "t1");
        
        
        
        //监控变量的变化,做出反应
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    if(list1.size() == 5){
                        System.out.println("当前线程收到通知:" + Thread.currentThread().getName() + " list size = 5 线程停止..");
                        throw new RuntimeException();
                    }
                }
            }
        }, "t2");        
        
        
        //启动线程
        t1.start();
        t2.start();
    }
    
    
}

 

 结果

当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..

 线程2 并没有监控到 变量的变化

使用 volatile ,进行声明

    //变量
    private volatile  static List list = new ArrayList();

结果

当前线程收到通知:t2 list size = 5 线程停止..
Exception in thread "t2" java.lang.RuntimeException
    at test19218.ListAdd1$2.run(ListAdd1.java:54)
    at java.lang.Thread.run(Unknown Source)
当前线程:t1添加了一个元素..
当前线程:t1添加了一个元素..

线程2 监控到了 变量的变化

概念

CountDownLatch

是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程执行完后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有框架服务之后执行。
CountDownLatch的用法

CountDownLatch典型用法1:某一线程在开始运行前等待n个线程执行完毕。将CountDownLatch的计数器初始化为n new CountDownLatch(n) ,每当一个任务线程执行完毕,就将计数器减1 countdownlatch.countDown(),当计数器的值变为0时,在CountDownLatch上 await() 的线程就会被唤醒。一个典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行。

CountDownLatch典型用法2:实现多个线程开始执行任务的最大并行性。注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的CountDownLatch(1),将其计数器初始化为1,多个线程在开始执行任务前首先 coundownlatch.await(),当主线程调用 countDown() 时,计数器变为0,多个线程同时被唤醒。
 

也可使用lock的wait和notif

package test19218;

import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;
/**
 * wait notfiy 方法,wait释放锁,notfiy不释放锁
 * @author alienware
 *
 */
public class ListAdd2 {
    private  volatile  static List list = new ArrayList();    
    
    public void add(){
        list.add("bjsxt");
    }
    public int size(){
        return list.size();
    }
    
    public static void main(String[] args) {
        
        final ListAdd2 list2 = new ListAdd2();
        
        // 1 实例化出来一个 lock
        // 当使用wait 和 notify 的时候 , 一定要配合着synchronized关键字去使用
        //final Object lock = new Object();
        
        final CountDownLatch countDownLatch = new CountDownLatch(1);
        
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //synchronized (lock) {
                        for(int i = 0; i <10; i++){
                            list2.add();
                            System.out.println("当前线程:" + Thread.currentThread().getName() + "添加了一个元素..");
                            Thread.sleep(500);
                            if(list2.size() == 5){
                                System.out.println("已经发出通知..");
                                countDownLatch.countDown();
                                //lock.notify();
                            }
                        }                        
                    //}
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }, "t1");
        
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                //synchronized (lock) {
                    if(list2.size() != 5){
                        try {
                            //System.out.println("t2进入...");
                            //lock.wait();
                            countDownLatch.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println("当前线程:" + Thread.currentThread().getName() + "收到通知线程停止..");
                    throw new RuntimeException();
                //}
            }
        }, "t2");    
        
        t2.start();
        t1.start();
        
    }
    
}

 

这里是否使用volatile 都不会影响结果!!!

对象的lock和notify

package com.bjsxt.base.conn009;

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class MyQueue {
    
    //1 需要一个承装元素的集合
    private LinkedList<Object> list = new LinkedList<Object>();
    
    //2 需要一个计数器
    private AtomicInteger count = new AtomicInteger(0);
    
    //3 需要制定上限和下限
    private final int minSize = 0;
    
    private final int maxSize ;
    
    //4 构造方法
    public MyQueue(int size){
        this.maxSize = size;
    }
    
    //5 初始化一个对象 用于加锁
    private final Object lock = new Object();
    
    
    //put(anObject): 把anObject加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻断,直到BlockingQueue里面有空间再继续.
    public void put(Object obj){
        synchronized (lock) {
            while(count.get() == this.maxSize){
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //1 加入元素
            list.add(obj);
            //2 计数器累加
            count.incrementAndGet();
            //3 通知另外一个线程(唤醒)
            lock.notify();
            System.out.println("新加入的元素为:" + obj);
        }
    }
    
    
    //take: 取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到BlockingQueue有新的数据被加入.
    public Object take(){
        Object ret = null;
        synchronized (lock) {
            while(count.get() == this.minSize){
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //1 做移除元素操作
            ret = list.removeFirst();
            //2 计数器递减
            count.decrementAndGet();
            //3 唤醒另外一个线程
            lock.notify();
        }
        return ret;
    }
    
    public int getSize(){
        return this.count.get();
    }
    
    
    public static void main(String[] args) {
        
        final MyQueue mq = new MyQueue(5);
        mq.put("a");
        mq.put("b");
        mq.put("c");
        mq.put("d");
        mq.put("e");
        
        System.out.println("当前容器的长度:" + mq.getSize());
        
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                mq.put("f");
                mq.put("g");
            }
        },"t1");
        
        t1.start();
        
        
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                Object o1 = mq.take();
                System.out.println("移除的元素为:" + o1);
                Object o2 = mq.take();
                System.out.println("移除的元素为:" + o2);
            }
        },"t2");
        
        
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        t2.start();
        
        
    }
    
    
    
}

 

ThreadLocal

声明为线程私有

假如不声明:

package test19218;

public class ConnThreadLocal {

    //public static ThreadLocal<String> th = new ThreadLocal<String>();
    
    public String th = "";
    
    public void setTh(String value){
        //th.set(value);
        
        this.th = value;
    }
    public void getTh(){
        //System.out.println(Thread.currentThread().getName() + ":" + this.th.get());
        
        System.out.println(Thread.currentThread().getName() + ":" + this.th);
    }
    
    public static void main(String[] args) throws InterruptedException {
        
        final ConnThreadLocal ct = new ConnThreadLocal();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                ct.setTh("张三");
                ct.getTh();
            }
        }, "t1");
        
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    ct.getTh();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "t2");
        
        t1.start();
        t2.start();
    }
    
}

 

 结果

t1:张三
t2:张三

 声明为私有:

package test19218;

public class ConnThreadLocal {

    public static ThreadLocal<String> th = new ThreadLocal<String>();
    
    //public String th = "";
    
    public void setTh(String value){
        th.set(value);
        
        //this.th = value;
    }
    public void getTh(){
        System.out.println(Thread.currentThread().getName() + ":" + this.th.get());
        
        //System.out.println(Thread.currentThread().getName() + ":" + this.th);
    }
    
    public static void main(String[] args) throws InterruptedException {
        
        final ConnThreadLocal ct = new ConnThreadLocal();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                ct.setTh("张三");
                ct.getTh();
            }
        }, "t1");
        
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                    ct.getTh();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "t2");
        
        t1.start();
        t2.start();
    }
    
}

 

 结果:

t1:张三
t2:null

 使用单列

package test19218;

public class DubbleSingleton {

    private static DubbleSingleton ds;
    
    public  static DubbleSingleton getDs(){
        if(ds == null){
            try {
                //模拟初始化对象的准备时间...
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (DubbleSingleton.class) {
                if(ds == null){
                    ds = new DubbleSingleton();
                }
            }
        }
        return ds;
    }
    
    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(DubbleSingleton.getDs().hashCode());
            }
        },"t1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(DubbleSingleton.getDs().hashCode());
            }
        },"t2");
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(DubbleSingleton.getDs().hashCode());
            }
        },"t3");
        
        t1.start();
        t2.start();
        t3.start();
    }
    
}

 

 结果

702577982
702577982
702577982

 hashcode一致,说明是同一个对象

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值