首页 > 编程语言 > 详细

线程高级应用-心得3-线程范围内的共享变量以及应用场景及面试题案例分析

时间:2017-01-08 14:14:41      阅读:333      评论:0      收藏:0      [点我收藏+]

1.知识点普及

技术分享

技术分享

技术分享

技术分享

2.案例说明:线程范围内的共享变量以及应用场景(转账,转入和转出);在线程内共享,在线程外独立

package com.itcast.family;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * 案例说明:线程范围内的共享变量以及应用场景(转账,转入和转出);在线程内共享,在线程外独立
 */
public class ThreadScopeShareData {

    //使不同模块拿到相同线程的相同数据
    private static Map<Thread,Integer> threadData = new HashMap<Thread, Integer>();
    public static void main(String[] args) {
        for (int i = 0; i < 2; i++) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    int data = new Random().nextInt();
                    System.out.println(Thread.currentThread().getName()
                            + " has put data: " + data);
                    threadData.put(Thread.currentThread(), data);
                    new A().get();
                    new B().get();
                }
            }).start();
        }
    }

    static class A {
        public void get() {
            int data = threadData.get(Thread.currentThread());
            System.out.println("A from " + Thread.currentThread().getName()
                    + " get data: " + data);
        }
    }

    static class B {
        public void get() {
            int data = threadData.get(Thread.currentThread());
            System.out.println("B from " + Thread.currentThread().getName()
                    + " get data: " + data);
        }
    }
}
3. 使用ThreadLocal达到与上个案例相同的需求
package com.itcast.family;

import java.util.Random;

/**
 * 使用ThreadLocal达到与上个案例相同的需求
 */
public class ThreadLocalTest {


    //使不同模块拿到相同线程的相同数据
    //直接使用ThreadLocal传入数据
    private static ThreadLocal<Integer> threadData = new ThreadLocal<Integer>();
    //使用ThreadLocal传入对象中封装的数据;普通思路用到的变量
    //private static ThreadLocal<MyThreadScopeData> myData = new ThreadLocal<MyThreadScopeData>();
    public static void main(String[] args) {
        for (int i = 0; i < 2; i++) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    int data = new Random().nextInt();
                    System.out.println(Thread.currentThread().getName()
                            + " has put data: " + data);
                    threadData.set(data);
                    
                    //一般思路,符合基本的面向对象编程,但是用着啰嗦臃肿,代码不够优化    
/*                    MyThreadScopeData myThread = new MyThreadScopeData();
                    myThread.setName("get nameData: "+data);
                    myThread.setAge(data);
                    myData.set(myThread);*/
                    
                    
                    //优雅和优化的思路,类似单例模式封装代码,因为使用者只需知道怎么用干什么用的,而不需知道内部代码是什么
                    MyThreadScopeData.getThreadInstance().setName(" get nameData: "+data);
                    MyThreadScopeData.getThreadInstance().setAge(data);
                    new A().get();
                    new B().get();
                }
            }).start();
        }
    }

    static class A {
        public void get() {
            int data = threadData.get();
            System.out.println("A from " + Thread.currentThread().getName()
                    + " get data: " + data);
    
            //一般思路,符合基本的面向对象编程,但是用着啰嗦臃肿,代码不够优化
/*            MyThreadScopeData myThread = myData.get();
            System.out.println("A from " + Thread.currentThread().getName()
                     + myThread.getName()+" ;get ageData: "+myThread.getAge());*/
            
            
            //优雅和优化的思路,类似单例模式封装代码,因为使用者只需知道怎么用干什么用的,而不需知道内部代码是什么
            MyThreadScopeData myThread = MyThreadScopeData.getThreadInstance();
            System.out.println("A from " + Thread.currentThread().getName()
                     + myThread.getName()+" ; get ageData: "+myThread.getAge());
        }
    }

    static class B {
        public void get() {
            int data = threadData.get();
            System.out.println("B from " + Thread.currentThread().getName()
                    + " get data: " + data);
            
/*            MyThreadScopeData myThread = myData.get();
            System.out.println("B from " + Thread.currentThread().getName()
                     + myThread.getName()+" ;get ageData: "+myThread.getAge());*/
            
            MyThreadScopeData myThread = MyThreadScopeData.getThreadInstance();
            System.out.println("B from " + Thread.currentThread().getName()
                     + myThread.getName()+" ; get ageData: "+myThread.getAge());
        }
    }
}

class MyThreadScopeData{
    //可以参考单例模式来编写更加优化和优雅的线程代码
    private MyThreadScopeData(){}
     //线程这里与单例有些许不同,因为只有一个对象,所以可以不用使用同步锁
    public static/*synchronized*/MyThreadScopeData getThreadInstance(){
        MyThreadScopeData instance = map.get();
        if(instance == null){
            instance = new MyThreadScopeData();
            map.set(instance);
        }
        return instance;
    }
    
    /*只是告诉阅读者类似单例代码,但是与单例不同
     * private static MyThreadScopeData intance = null;//new MyThreadScopeData(); 
    //饱汉式,不管用不用先new出来;这里用饿汉式,用的时候才new出来
    */    
    private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    
}
4. 面试题: 设计4个成员,其中两个线程每次对j加1;另两个线程每次对j减1,代码如下分析:

package com.itcast.family;

/**
 * 面试题:
 *    设计4个成员,其中两个线程每次对j加1;
 * 另两个线程每次对j减1,代码如下分析:
 */
public class MultiThreadShareData {
    
    // 面试题答案:
    private int j;

    public static void main(String[] args) {
        MultiThreadShareData data = new MultiThreadShareData();
        Inc inc = data.new Inc();
        Dec dec = data.new Dec();
        //创建四个线程,如题:两个增加两个减少
        for (int i = 0; i < 2; i++) {
            new Thread(inc).start();
            new Thread(dec).start();
        }
    }

    /*
     * 不直接把j++或j--写到对应的实现Runnable类的代码中,
     * 而是抽出成外部类的两个方法;是因为外部类的方法方便使用
     * 同步锁,更容易控制并发问题
     */
    private synchronized void inc() {
        j++;
        System.out.println(Thread.currentThread().getName() + "-inc:" + j);
    }

    private synchronized void dec() {
        j--;
        System.out.println(Thread.currentThread().getName() + "-dec:" + j);
    }

    class Inc implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                inc();
            }
        }

    }

    class Dec implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                dec();
            }
        }

    }
    
    

    
    /*//第一种方案传入的data变量要么是静态成员变量要么是最终普通变量,否则会出错;因为两个内部类访问可以访问同一个外部类的成员变量
    private static ShareData data1 = new ShareData();
    public static void main(String[] args) {
        final ShareData data1 = new ShareData();
        ShareData data2 = new ShareData();
        
        //第一种方案:这两个线程分别实现两个Runnable的run方法,分别用来执行加减
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                data1.increment();
            }
        }).start();
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                data1.decrement();
            }
        }).start();
        
        //第二种方案:传入实现了Runnable接口的类对象,相应的需求方法封装在传入的类中
        new Thread(new MyRunnable1(data2)).start();
        new Thread(new MyRunnable2(data2)).start();

    }

}

//第二种方案
class MyRunnable1 implements Runnable{
    private ShareData data;
    MyRunnable1(ShareData data) {
        super();
        this.data = data;
    }

    public void run() {
        data.increment();
    }
}
class MyRunnable2 implements Runnable{
    private ShareData data;
    MyRunnable2(ShareData data) {
        super();
        this.data = data;
    }
    
    public void run() {
        data.decrement();
    }
}


//因为需求是一个加一个减,即两个不同的线程,仅实现一个Runnable接口是不够的
class ShareData{ implements Runnable{
    private int count = 100;
    @Override
    public void run() {
        while(true){
            count --;
        }
    }
   
    private int j = 0;
    public void increment(){
        j++;
    }
    public void decrement(){
        j--;

    }
    */
}

 

 

线程高级应用-心得3-线程范围内的共享变量以及应用场景及面试题案例分析

原文:http://www.cnblogs.com/cxxjohnson/p/6261889.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!