zoukankan      html  css  js  c++  java
  • 传统线程的创建方式

    传统线程技术回顾

    public class TraditionalThread {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
          //第一种:new Thread()
            Thread thread = new Thread(){
                @Override
                public void run() {
                    while(true){
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("1:" + Thread.currentThread().getName());
                        System.out.println("2:" + this.getName());
                    }
                }
            };
            thread.start();
            
            
            Thread thread2 = new Thread(new Runnable(){
                @Override
                public void run() {
                    while(true){
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("1:" + Thread.currentThread().getName());
    
                    }                
                    
                }
            });
            thread2.start();
            
            //第二种:new Runnable()
            new Thread(
                    new Runnable(){
                        public void run() {
                            while(true){
                                try {
                                    Thread.sleep(500);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
                                System.out.println("runnable :" + Thread.currentThread().getName());
    
                            }                            
                        }
                    }
            ){
                public void run() {
                    while(true){
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("thread :" + Thread.currentThread().getName());
    
                    }    
                }
            }.start();
            
            
        }
    
    }


    传统定时器技术回顾

    第一次2秒后输出"bombing" 第二次4秒后输出“bombing”,第三次2秒后输出"bombing" 第四次4秒后输出“bombing”

    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class TraditionalTimerTest {
    
        private static int count = 0;
        public static void main(String[] args) {
    /*        new Timer().schedule(new TimerTask() {
                
                @Override
                public void run() {
                    System.out.println("bombing!");
                    
                }
            }, 10000,3000);*/
            
    
            class MyTimerTask extends TimerTask{
                
                @Override
                public void run() {
                    count = (count+1)%2;
                    System.out.println("bombing!");
                    new Timer().schedule(/*new TimerTask() {
                        
                        @Override
                        public void run() {
                            System.out.println("bombing!");
                        }
                    }*/new MyTimerTask(),2000+2000*count);
                }
            }
            
            new Timer().schedule(new MyTimerTask(), 2000);
            
            while(true){
                System.out.println(new Date().getSeconds());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    
    }


    传统线程互斥技术

    public class TraditionalThreadSynchronized {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            new TraditionalThreadSynchronized().init();
        }
        
        private void init(){
            final Outputer outputer = new Outputer();
            new Thread(new Runnable(){
                @Override
                public void run() {
                    while(true){
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        outputer.output("zhangxiaoxiang");
                    }
                    
                }
            }).start();
            
            new Thread(new Runnable(){
                @Override
                public void run() {
                    while(true){
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        outputer.output3("lihuoming");
                    }
                    
                }
            }).start();
            
        }
    
        static class Outputer{
            
            public void output(String name){
                int len = name.length();
            //synchronized 必须使用同一个对象
    synchronized (Outputer.class) { for(int i=0;i<len;i++){ System.out.print(name.charAt(i)); } System.out.println(); } } public synchronized void output2(String name){ int len = name.length(); for(int i=0;i<len;i++){ System.out.print(name.charAt(i)); } System.out.println(); } public static synchronized void output3(String name){ int len = name.length(); for(int i=0;i<len;i++){ System.out.print(name.charAt(i)); } System.out.println(); } } }


    传统线程同步通信技术

     例子:子线程循环10次,接着主线程循环100次,接着又回到子线程循环10次,接着再回到主线程又循环100次,如此循环50次

    import java.util.concurrent.atomic.AtomicInteger;
    
    public class TraditionalThreadCommunication {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            
            final Business business = new Business();
            new Thread(
                    new Runnable() {
                        
                        @Override
                        public void run() {
                        
                            for(int i=1;i<=50;i++){
                                business.sub(i);
                            }
                            
                        }
                    }
            ).start();
            
            for(int i=1;i<=50;i++){
                business.main(i);
            }
            
        }
    
    }
      class Business {
          private boolean bShouldSub = true;
          public synchronized void sub(int i){
              while(!bShouldSub){
                  try {
                    this.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
              }
                for(int j=1;j<=10;j++){
                    System.out.println("sub thread sequence of " + j + ",loop of " + i);
                }
              bShouldSub = false;
              this.notify();
          }
          
          public synchronized void main(int i){
                  while(bShouldSub){
                      try {
                        this.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                  }
                for(int j=1;j<=100;j++){
                    System.out.println("main thread sequence of " + j + ",loop of " + i);
                }
                bShouldSub = true;
                this.notify();
          }
      }


    线程范围内共享变量的概念与作用

         ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量。

      这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线程都在操作同一个变量,显然是不行的,并且我们也知道volatile这个关键字也是不能保证线程安全的。那么在有一种情况之下,我们需要满足这样一个条件:变量是同一个,但是每个线程都使用同一个初始值,也就是使用同一个变量的一个新的副本。这种情况之下ThreadLocal就非常使用,比如说DAO的数据库连接,我们知道DAO是单例的,那么他的属性Connection就不是一个线程安全的变量。而我们每个线程都需要使用他,并且各自使用各自的。这种情况,ThreadLocal就比较好的解决了这个问题。

     我们从源码的角度来分析这个问题。

      首先定义一个ThreadLocal:

    复制代码
    public class ConnectionUtil {
        private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
        private static Connection initConn = null;
        static {
            try {
                initConn = DriverManager.getConnection("url, name and password");
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        
        public Connection getConn() {
            Connection c = tl.get();
            if(null == c) tl.set(initConn);
            return tl.get();
        }
        
    }
    复制代码

      这样子,都是用同一个连接,但是每个连接都是新的,是同一个连接的副本。

      那么实现机制是如何的呢?

      1、每个Thread对象内部都维护了一个ThreadLocalMap这样一个ThreadLocal的Map,可以存放若干个ThreadLocal。

    1
    2
    3
    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;

      2、当我们在调用get()方法的时候,先获取当前线程,然后获取到当前线程的ThreadLocalMap对象,如果非空,那么取出ThreadLocal的value,否则进行初始化,初始化就是将initialValue的值set到ThreadLocal中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }

      3、当我们调用set()方法的时候,很常规,就是将值设置进ThreadLocal中。

      4、总结:当我们调用get方法的时候,其实每个当前线程中都有一个ThreadLocal。每次获取或者设置都是对该ThreadLocal进行的操作,是与其他线程分开的。

      5、应用场景:当很多线程需要多次使用同一个对象,并且需要该对象具有相同初始化值的时候最适合使用ThreadLocal。

      6、其实说再多也不如看一下源码来得清晰。如果要看源码,其中涉及到一个WeakReference和一个Map,这两个地方需要了解下,这两个东西分别是a.Java的弱引用,也就是GC的时候会销毁该引用所包裹(引用)的对象,这个threadLocal作为key可能被销毁,但是只要我们定义成他的类不卸载,tl这个强引用就始终引用着这个ThreadLocal的,永远不会被gc掉。b.和HashMap差不多。

      事实上,从本质来讲,就是每个线程都维护了一个map,而这个map的key就是threadLocal,而值就是我们set的那个值,每次线程在get的时候,都从自己的变量中取值,既然从自己的变量中取值,那肯定就不存在线程安全问题,总体来讲,ThreadLocal这个变量的状态根本没有发生变化,他仅仅是充当一个key的角色,另外提供给每一个线程一个初始值。如果允许的话,我们自己就能实现一个这样的功能,只不过恰好JDK就已经帮我们做了这个事情。


    ThreadLocal类及应用技巧
    多个线程之间共享数据的方式探讨
    java5原子性操作类的应用
    java5线程并发库的应用
    Callable与Future的应用
    java5的线程锁技术
    java5读写锁技术的妙用
    java5条件阻塞Condition的应用
    java5的Semaphere同步工具
    java5的CyclicBarrier同步工具
    java5的CountDownLatch同步工具
    java5的Exchanger同步工具
    java5阻塞队列的应用
    java5同步集合类的应用
    空中网挑选实习生的面试题1
    空中网挑选实习生的面试题2
    空中网挑选实习生的面试题3


  • 相关阅读:
    洛谷3703 [SDOI2017] 树点染色 【LCT】【线段树】
    BZOJ4818 [SDOI2017] 序列计数 【矩阵快速幂】
    HDU4625 JZPTREE 【树形DP】【第二类斯特林数】
    LOJ2116 [HNOI2015] 开店 【点分治】
    [NOIP2017] 逛公园 【最短路】【强连通分量】
    css
    html
    spring-springmvc-jdbc小案例
    eclipse myeclipse中的一些配置
    springmvc中的一些服务器报错
  • 原文地址:https://www.cnblogs.com/xuyatao/p/6718717.html
Copyright © 2011-2022 走看看