疯子在思考之java 线程的那点事儿 -买球官网平台

`
zh_harry
  • 浏览: 91166 次
  • 性别:
  • 来自: 北京
博主相关
  • 博客
  • 微博
  • 相册
  • 收藏
  • 博客专栏
    自己动手写java 框架
    浏览量:24951
    社区版块
    • ( 0)
    • ( 12)
    • ( 0)
    存档分类
    最新评论

    疯子在思考之java 线程的那点事儿

      博客分类:
    • java
    很长时间没写博客了,最近事情比较多
    之前在文章中提到过tomcat 的main函数在哪?被很多朋友拍砖了
    今天继续就这话题展开,先了解几个线程有关的概念
    1、多线程 multithread
    为什么要用多线程?就是让cpu别太闲,有空就要干活,提高效率。
    2、线程池 threadpool
    为什么要用线程池,所有跟池相关的,如connectionpool(数据库连接池),ajax request请求对 象池、线程池等都是为了减少对象new所带来的开销.
    3、线程安全 thread safe
    所谓的线程安全就是指多线程的运行结果与单线程的运行结果一致,java 通过synchronized和threadlocal等解决线程安全问题。
    线程不安全是由于对共享资源(如static 变量 单例成员变量 文件 数据库 缓存等)的同步写操作而引起的。

    tomcat 的main在这里
    它会启动一个servicesoket监听客户端socket请求.
    org.apache.catalina.startup.bootstrap.java
    具体功能有一本书《深入剖析tomcat》有兴趣的朋友可以了解一下。
    我们先用最简单的socket 看看他的工作原理
    服务器 socket代码
    package service;
    import java.io.bufferedreader;
    import java.io.ioexception;
    import java.io.inputstreamreader;
    import java.io.printwriter;
    import java.net.serversocket;
    import java.net.socket;
    public class servicesocketdemo {
    	/**
    	 * @author zlz
    	 * 
    	 * @time 2013-7-26下午5:00:04
    	 * @param args
    	 * @throws ioexception
    	 */
    	public static void main(string[] args) throws ioexception {
                    //服务器端启动后会不停地监听该端口请求
    		serversocket serversocket = new serversocket(1999);
    		while (true) {
                            //接受请求
    			socket socket = serversocket.accept();
    			bufferedreader br = new bufferedreader(new inputstreamreader(
    					socket.getinputstream()));
    			string msg = null;
    			if ((msg = br.readline()) != null) {
    				system.out.println("服务器端收到—->"   msg);
    			}
    			printwriter pw = new printwriter(socket.getoutputstream(), true);
                             
    //处理后并输出到客户端
    			pw.println("hi");
    			socket.close();
    		}
    	}
    }
    


    客户端socket代码
    package client;
    import java.io.bufferedreader;
    import java.io.ioexception;
    import java.io.inputstreamreader;
    import java.io.printwriter;
    import java.net.socket;
    import java.net.unknownhostexception;
    public class clientsocketdemo {
    	/**
    	 * @author zlz
    	 * 
    	 * @time 2013-7-26下午5:03:52
    	 * @param args
    	 * @throws ioexception
    	 * @throws unknownhostexception
    	 */
    	public static void main(string[] args) throws unknownhostexception,
    			ioexception {
                    //请求127.0.0.1:1999端口
    		socket socket = new socket("127.0.0.1", 1999);
    		printwriter pw = new printwriter(socket.getoutputstream(), true);
                    //发送hello 并等待服务器端处理
    		pw.println("helllo");                
    		bufferedreader br = new bufferedreader(new inputstreamreader(
    				socket.getinputstream()));
    		string msg = null;
    		if ((msg = br.readline()) != null) {
    			system.out.println("客户端收到—->"   msg);
    		}
    	}
    }
    


    沿着多线程的思路给这个最简单的socket加上多线程
    方案1:将请求的数据扔给线程(这个方案是行不通的,因为数据处理完毕之后无法返回给客户端,需要返回到主线程处理,这就相当于是脱了裤子放屁,多此一举)
    方案2:将socket对象扔给线程(这一点其实很重要,主线程不要再关心子线程的处理结果,下面要继续说到主线程需要关心子线程结果的情况 mapreduce)

    方案2是多线程的一种实现方案,但是还不够优化,每次请求都要new一个线程,增大了服务器的压力,所以tomcat引入了threadpool的概念。
    实现threadpool与其他的pool不太一样,因为线程程行完成之后就不能再restart了,即一旦执行完成将不能再复用。那么怎么实现线程池呢?

    解决办法:在线程内while无线循环,永远不死。

    继续拿tomcat的例子
    tomcat会有一个sockt队列(当然对它的访问要线程安全的)
    主线程负责生产
    子线程负责处理
    即生产者/消费者模式
    显然这里比上边的多线程多了一个队列,这是我所理解的线程池概念,有异意大家批评。

    刚才提到这里的主线程不需要子线程返回结果
    而有些场景我们是需要子线程反馈的,比如mapreduce,它是将一份数据(一般比较大)
    分成n份给n个线程这是map的过程,然后每个线程的处理结果在汇总到主线程这是reduce的过程。那么就需要线程间通信。
    线程通过需要全局变量,即主线程和子线程共享能够访问的变量。
    举一个简单例子
    比如一本汉语字典,要查一下字典中一共有多少个字,那么我们分成n个线程去同步处理。
    需要一个变量去统计已经处理的线程总数(dealedthreadcount),还有一个字典对象。
    这个变量一定是共享的(或者是static 或者所在类是单例的)
    那么主线程的处理逻辑应该是这样的
    伪代码:
    static integer dealedthreadcount
    synchronized(dealedthreadcount){
        for(int i=0;i      //子线程处理
          new dealthread(i).start();
        }
        //主线程等待
        dealedthreadcount.wait();
    }

    子线程代码
    ...
    dealedthreadcount ;
    if(dealedthreadcount==n)
    {
    dealedthreadcount.nodify();通知主线程reduce
    }

    总结:
    synchronized的变量只要是全局共享的即可,可以没有任何意义,为了实现线程间通信
    需要synchronized wait notify 辅助完成
    一般出现wait notify的情况一定会出现synchronized,反之则不一定。



    最后一点关于线程安全的threadlocal
    见这里


    这里继续说一下,上边的链接讲了threadlocal原理及java sdk 的代码分析。
    那么什么场景应用呢?
    我所了解的有两个地方
    第一 数据库访问时的session对象
    第二 不知道朋友们思考过没有,strtus 2.0有一个actionsupport对象,这里会注入request response等对象
    是因为他们是多实例对象所以不会有问题,那么如果我想把它定义成单例的(spring mvc是这样做的)就会有线程安全问题。而且我们同样要继承该类,那么就需要threadlocal变量。


    线程安全问题非常值得注意
    比如jdk里的很多对象都是线程不安全的,而有些变量看起来是不安全的,而实际上又是安全的。举两个例子

    //线程安全的 getinstance一般为单例的方法,但jdk里每次都会new 一个变量出现。
    calendar c=calendar.getinstance();
     /**
         * gets a calendar using the default time zone and locale. the
         * calendar returned is based on the current time
         * in the default time zone with the default locale.
         *
         * @return a calendar.
         */
        public static calendar getinstance()
        {
            calendar cal = createcalendar(timezone.getdefaultref(), locale.getdefault());
    	cal.sharedzone = true;
    	return cal;
        }
     private static calendar createcalendar(timezone zone,
    					   locale alocale)
        {
    	// if the specified locale is a thai locale, returns a buddhistcalendar
    	// instance.
    	if ("th".equals(alocale.getlanguage())
    	    && ("th".equals(alocale.getcountry()))) {
    	    return new sun.util.buddhistcalendar(zone, alocale);
    	} else if ("jp".equals(alocale.getvariant())
    		   && "jp".equals(alocale.getcountry())
    		   && "ja".equals(alocale.getlanguage())) {
    	    return new japaneseimperialcalendar(zone, alocale);
    	}	    
    	// else create the default calendar
            return new gregoriancalendar(zone, alocale);	
        }
    


    第二个
    dateformat s=simpledateformat.getinstance();
    都是非单例对象,即是线程安全的
    但是每次new的开销是比较大的,当数据量访问量非常大时会导致cpu过高,解决办法也是通过threadlocal


    jdk中其他线程问题,各位大拿可以补充,谢谢!
    3
    4
    分享到:
    |
    评论
    7 楼 zh_harry 2013-08-16  
    wxl24life 写道
    楼主好文,提几个明显的概念上的误解

    1、
    引用
    为什么要用线程池,所有跟池相关的,如connectionpool(数据库连接池),ajax request请求对 象池、线程池等都是为了减少对象new所带来的开销.


    java 1.5 提供的线程池的作用可远不只是为了减少 new thread 的开销问题哦

    2、
    引用
    线程不安全是由于对共享资源(如static 变量 单例成员变量 文件 数据库 缓存等)的同步写操作而引起的。


    这里是另一个很严重的误解,线程安全问题是由于对共享可变资源的读写并发访问产生的

    1.5的线程池我还不了解,还停留在1.4版本上
    共享可变是对的(我文中也说的是变量,并不是常量),但主要是写操作,读操作不产生线程不安全问题
    6 楼 2013-08-15  
    这种网络io,建议用nio实现,异步非阻塞。
    5 楼 2013-08-15  
    楼主好文,提几个明显的概念上的误解

    1、
    引用
    为什么要用线程池,所有跟池相关的,如connectionpool(数据库连接池),ajax request请求对 象池、线程池等都是为了减少对象new所带来的开销.


    java 1.5 提供的线程池的作用可远不只是为了减少 new thread 的开销问题哦

    2、
    引用
    线程不安全是由于对共享资源(如static 变量 单例成员变量 文件 数据库 缓存等)的同步写操作而引起的。


    这里是另一个很严重的误解,线程安全问题是由于对共享可变资源的读写并发访问产生的
    4 楼 zh_harry 2013-08-15  
    quarterlifeforjava 写道
    就是说,我们只要用别人的就行了,会用就可以了。怎么开发出来的,开发的痛苦是老外承受着的

    是这个意思
    我现在在想链接池和log4j的实现
    datasource只有getconnection接口有用,log4j和jtli怎么兼容?tomcat做到了
    dbcp和c3p0怎么搞的?
    有兴趣的一起讨论
    3 楼 2013-08-15  
    就是说,我们只要用别人的就行了,会用就可以了。怎么开发出来的,开发的痛苦是老外承受着的
    2 楼 zh_harry 2013-08-15  
    lvwenwen 写道
    看到国外开发人员的痛苦,我内心很淡定的安慰了自己。

    神马意思?
    1 楼 2013-08-14  
    看到国外开发人员的痛苦,我内心很淡定的安慰了自己。

    相关推荐

      疯子卸载java.zip

      《天才在左疯子在右》的基本介绍和推荐理由[定义].pdf

      疯子手机apk卸载工具疯子手机apk卸载工具疯子手机apk卸载工具疯子手机apk卸载工具疯子手机apk卸载工具疯子手机apk卸载工具疯子手机apk卸载工具疯子手机apk卸载工具疯子手机apk卸载工具疯子手机apk卸载工具疯子手机...

      疯子助手是一款为苹果设备用户提供应用下载和游戏破解的软件,疯子助手里提供了海量不闪退应用和近千款极高有效度的ios热门游戏存档。 疯子助手完美支持不越狱的iphone和ipad等ios设备,是一款下载安装和管理软件、...

      android疯子卸载

      疯子锁ie插件,锁ie,锁ie插件 懒人锁ie ie加锁 锁ie买球官网平台主页 ie买球买球官网平台官网平台首页被锁 ie代理设置被锁

      疯子ftp上传工具源码传送数据到服务器源码版.rar

      读后感ۥ天才在左疯子在右精选.doc

      疯子ftp上传工具传送数据到服务器 ftp上传工具 ftp服务器上传 ftp客户端 ftp服务器客户端 2.0新功能 密码加密 在线更新 更新缓存错误

      读后感《天才在左,疯子在右》.doc

      java 8 新特性之lamdbas介绍,本书中介绍了lambdas的用法,以及示例等

      资源是在java代码中采用javaemail来实现发邮件的功能

      疯子页面采集器是一款网页抓取工具,是用于网站信息采集,网站信息抓取,包括图片、文字等信息采集处理发布,是目前使用人数最多的互联网数据采集程序,可以采集大部分未加密页面站点。

      java小程序,适合初学者参考,用myeclipse开发,包括源码和.java文件

      java读取dbf文件jar包javadbf.jar,像高考分数一般导出都是dbf文件。

      疯子苹果助手是一款最受欢迎的应用下载平台,不越狱装软件的唯一选择、海量正版软件游戏、每日都有新增、全部免费安装,不需理会手机是否越狱,这么神奇助手,大家赶紧下载使用。 疯子苹果助手软件截图

      里面的错误总结是本人学java是总结出来的错误,大部分的错误都在里面,者是为了让java学者不为错误而发愁

      查询必备,每当写java代码的时候都需要进行这方面的查询,高手就不用看了

      sm3杂凑算法在java上的实现,提供输入要杂凑的信息,输出杂凑后的结果(以16进制形式输出)。

      疯子

    global site tag (gtag.js) - google analytics