资讯专栏INFORMATION COLUMN

(四)java多线程之同步基础ThreadLocal

Lucky_Boy / 3287人阅读

摘要:本人邮箱欢迎转载转载请注明网址代码已经全部托管有需要的同学自行下载引言之前我们讲到都是多线程共享数据那么有没有某一个共享的变量在这变量里面每个线程都能拥有自己的属性呢比如说去旅店开房休息那么这个旅店就是一个共享的数据但是每个人开的房间是不一

本人邮箱:
欢迎转载,转载请注明网址 http://blog.csdn.net/tianshi_kco
github: https://github.com/kco1989/kco
代码已经全部托管github有需要的同学自行下载

引言

之前我们讲到都是多线程共享数据.那么有没有某一个共享的变量,在这变量里面,每个线程都能拥有自己的属性呢?比如说,去旅店开房休息.那么这个旅店就是一个共享的数据,但是每个人开的房间是不一样的.这个要怎么做呢?这里我先试着写一些

例子1

让我们编写一个程序,主线程开启十个子线程,然后每个子线程都做1~100的累加,都是共享同一个List,每个线程占有固定的位置进行累加计算

public class TestMain {

    public static class CalcRunnable implements Runnable{
        List list ;
        int index;
        public CalcRunnable(List list, int index) {
            this.list = list;
            this.index = index;
        }

        @Override
        public void run() {
            for (int i = 1; i <= 100; i++){
                list.set(index, list.get(index) + i);
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        List list = new ArrayList<>();
        List threads = new ArrayList<>();
        for (int i = 0; i < 10; i ++){
            list.add(0);
            threads.add(new Thread(new CalcRunnable(list,i)));
        }
        for (Thread thread : threads){
            thread.start();
        }

        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list);
    }
}

输出结果为

[5050, 5050, 5050, 5050, 5050, 5050, 5050, 5050, 5050, 5050]

这里每个线程都共享了list,但是也没有使用关键字synchronized进行同步,为什么结果还是正确的呢?原因很简单,那就是每个线程都使用固定的索引进行计算,互不干扰.所以结果不会受其他线程影响的.

例子2

现在把上面的例子中的List改为Map来做累加

public class TestMain1 {

    public static class CalcRunnable implements Runnable{
        Map map;
        public CalcRunnable(Map map) {
            this.map = map;
        }

        @Override
        public void run() {
            Thread self = Thread.currentThread();
            for (int i = 1; i <= 100; i++){
                map.put(self, map.get(self) + i);
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) {
        Map map = new HashMap<>();
        List threads = new ArrayList<>();
        for (int i = 0; i < 10; i ++){
            Thread thread = new Thread(new CalcRunnable(map));
            map.put(thread,0);
            threads.add(thread);
        }
        for (Thread thread : threads){
            thread.start();
        }

        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(map);
    }
}

运行结果

{Thread[Thread-1,5,]=5050, Thread[Thread-3,5,]=5050, Thread[Thread-6,5,]=5050, Thread[Thread-0,5,]=5050, Thread[Thread-8,5,]=5050, Thread[Thread-5,5,]=5050, Thread[Thread-7,5,]=5050, Thread[Thread-2,5,]=5050, Thread[Thread-4,5,]=5050, Thread[Thread-9,5,]=5050}

结果也是完全正确,道理跟上面的例子一样,每个线程虽然共用同一个数据map,但实际上每个线程都是用map中特定的那个元素

例子3

其实用map还有一种更简单的方式,那就是今天要讲的ThreadLocal,不废话,看例子

public class TestMain3 {

    public static class CalcRunnable implements Runnable{
        ThreadLocal threadLocal;
        public CalcRunnable(ThreadLocal threadLocal) {
            this.threadLocal = threadLocal;
        }

        @Override
        public void run() {
            threadLocal.set(0);//设置默认值
            for (int i = 1; i <= 100; i++){
                threadLocal.set(threadLocal.get() + i);
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + " 的计算结果为: " + threadLocal.get());
        }
    }

    public static void main(String[] args) {
        ThreadLocal threadLocal = new ThreadLocal<>();
        List threads = new ArrayList<>();
        for (int i = 0; i < 10; i ++){
            Thread thread = new Thread(new CalcRunnable(threadLocal));
            threads.add(thread);
        }
        for (Thread thread : threads){
            thread.start();
        }
    }
}

运行结果

Thread-0 的计算结果为: 5050
Thread-5 的计算结果为: 5050
Thread-1 的计算结果为: 5050
Thread-4 的计算结果为: 5050
Thread-7 的计算结果为: 5050
Thread-6 的计算结果为: 5050
Thread-3 的计算结果为: 5050
Thread-2 的计算结果为: 5050
Thread-8 的计算结果为: 5050
Thread-9 的计算结果为: 5050

原理,其实就是跟例子2的Map,在ThreadLocal中实现了一个ThreadLocalMap内部类,然后在调用ThreadLocal.getThreadLocal.set的时候,其实要获取当前线程去做相应的操作.

总结

如果以后大家想让多线程共享一个变量,但又不想互相影响的时候,那么首选ThreadLocal.因为对比上面三个例子,发现使用ThreadLocal是最简单的,而且不容易出错的.比如在web开发中,可以在多线程中存放session,或者数据库连接池的时候,也可以使用ThreadLocal在存放数据库连接.

打赏

如果觉得我的文章写的还过得去的话,有钱就捧个钱场,没钱给我捧个人场(帮我点赞或推荐一下)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/67042.html

相关文章

  • java高并发从零到放弃(

    摘要:前言本篇主要讲解如何去优化锁机制或者克服多线程因为锁可导致性能下降的问题线程变量有这样一个场景,前面是一大桶水,个人去喝水,为了保证线程安全,我们要在杯子上加锁导致大家轮着排队喝水,因为加了锁的杯子是同步的,只能有一个人拿着这个唯一的杯子喝 前言 本篇主要讲解如何去优化锁机制或者克服多线程因为锁可导致性能下降的问题 ThreadLocal线程变量 有这样一个场景,前面是一大桶水,10个...

    Alex 评论0 收藏0
  • Java线程同步与阻塞队列

    摘要:注意,和都是随机选择一个线程,解除其阻塞状态,可能会造成死锁。生产者线程向队列插入元素,消费者线程从队列取出元素。当添加时队列已满或取出时队列为空,阻塞队列导致线程阻塞。里面有个小技巧,一个线程搜索完毕时向阻塞队列填充,让所有线程能停下来。 多线程对共享数据的读写涉及到同步问题,锁和条件是线程同步的强大工具。锁用来保护代码片段(临界区),任何时刻只能有一个线程执行被保护的代码。条件对象...

    Olivia 评论0 收藏0
  • 想进大厂?50个线程面试题,你会少?(一)

    摘要:下面是线程相关的热门面试题,你可以用它来好好准备面试。线程安全问题都是由全局变量及静态变量引起的。持有自旋锁的线程在之前应该释放自旋锁以便其它线程可以获得自旋锁。 最近看到网上流传着,各种面试经验及面试题,往往都是一大堆技术题目贴上去,而没有答案。 不管你是新程序员还是老手,你一定在面试中遇到过有关线程的问题。Java语言一个重要的特点就是内置了对并发的支持,让Java大受企业和程序员...

    wow_worktile 评论0 收藏0
  • Java线程基础-ThreadLocal

    摘要:并没有提供语言级的线程局部变量,而是在类库里提供了线程局部变量的功能,也就是这次的主角类。 Yuicon 转载请注明原创出处,谢谢! 序 在多线程环境下,访问非线程安全的变量时必须进行线程同步,例如使用synchronized方式访问HashMap实例。但是同步访问会降低并发性,影响系统性能。这时候就可以用空间换时间,如果我们给每个线程都分配一个独立的变量,就可以用非同步的方式使用非...

    JasonZhang 评论0 收藏0
  • Java面试题必备知识ThreadLocal

    摘要:方法,删除当前线程绑定的这个副本数字,这个值是的值,普通的是使用链表来处理冲突的,但是是使用线性探测法来处理冲突的,就是每次增加的步长,根据参考资料所说,选择这个数字是为了让冲突概率最小。 showImg(https://segmentfault.com/img/remote/1460000019828633); 老套路,先列举下关于ThreadLocal常见的疑问,希望可以通过这篇学...

    Maxiye 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<