thread协议,短距离无线通信技术有哪些?各自的特点是什么
thread协议,短距离无线通信技术有哪些?各自的特点是什么详细介绍
本文目录一览: Thread协议栈基础
Thread协议栈是可靠,经济高效,低功耗,无线D2D(设备到设备)通信的开放标准。它是专为连接家庭应用而设计的,其中需要基于IP的网络,并且可以在协议栈中使用各种应用层。
这些是Thread协议栈和网络的一般特性:
图1显示了Thread协议栈的概述。
该标准基于在2.4GHz频带中以250kbps运行的IEEE 802.15.4 [IEEE802154] PHY(物理层)和MAC(媒体访问控制层)。该规范的IEEE 802.15.4-2006版本用于Thread协议栈。
802.15.4 MAC层用于基本的消息处理和拥塞控制。该MAC层包括设备用于监听干净信道的CSMA(Carrier Sense Multiple Access,载波侦听多路访问)机制,以及用于处理重试和确认消息的链路层以用于相邻设备之间的可靠通信。基于由软件协议栈的较高层建立和配置的密钥,被MAC层用于对消息的加密和完整性保护。网络层建立在这些基础机制上,以在网络中提供可靠的端对端通信。
在由运行Thread协议栈的设备组成的系统中,这些设备都不代表单点故障。虽然系统中有许多设备执行特殊功能,但是Thread协议栈的设计使得它们可以被替换,而不会影响Thread网络中正在进行的通信。例如,一个常眠的子设备需要一个父设备进行通信,因此这个父设备代表它的通信失败单点。但是,如果常眠设备的父设备不可用,常眠设备可以并将会选择另一个父设备,因此该转换不应该对用户可见。
虽然系统设计用于没有单点故障,但在某些拓扑结构下,将存在没有备份功能的单个设备。例如,在具有单个网关的系统中,如果网关断电,则无法切换到另一个网关。
路由器或边界路由器可以为Thread网络中的某些功能承担Leader角色。这个Leader需要在网络内作出决定。例如,Leader分配路由器地址并允许新的路由器请求。Leader角色是被选举的,如果Leader失败,会由另一个路由器或边界路由器承担Leader角色。正是这种自主操作确保没有单点故障。
边界路由器是一种特定类型的路由器,提供从802.15.4网络到其他物理层(例如,Wi-Fi和以太网)上的相邻网络的连接。边界路由器为802.15.4网络中的设备提供服务,包括用于离网操作(off-network operations)的路由服务。Thread网络中可能有一个或多个边界路由器。
路由器为网络设备提供路由服务。路由器还为尝试加入网络的设备提供加入和安全服务。路由器是设计为不休眠的。路由器可以降级其功能并成为REED(Router-eligible End Devices,符合路由器的终端设备)。
REED有能力成为路由器,但是由于网络拓扑或条件,这些设备不作为路由器工作。这些设备通常不转发消息或为Thread网络中的其他设备提供加入或安全服务。如果需要,Thread网络管理REED成为路由器,且无需用户交互。
常眠终端设备是主机设备。他们只通过他们的父路由器进行通信,不能转发其他设备的消息。
Thread协议栈中的设备支持[RFC 4291]中指定的IPv6寻址架构。设备配置1个或多个ULA(Unique Local Address,唯一本地地址)或GUA(Global Unicast Address,全局单播地址)地址。
启动网络的设备选择一个/64前缀,然后在整个Thread网络中使用。该前缀是本地分配的全局ID(Locally Assigned Global ID),通常称为ULA前缀[RFC 4193],可以称为网格本地ULA前缀(mesh local ULA prefix)。Thread网络还可以具有一个或多个边界路由器,每个边界路由器可以具有或可以不具有可以用于生成附加GUA的前缀。Thread网络中的设备使用其扩展MAC地址(Extended MAC address)来导出其[RFC 4944]第6节中定义的接口标识符(interface identifier),并且基于此,通过已知的本地前缀FE80 :: 0/64配置链路本地IPv6地址,如[RFC 4862]和[RFC 4944]所述。
设备还支持适当的多播地址(multicast addresses)。这包括链路本地所有节点组播(link-local all node multicast),链路本地全路由器组播(link-local all-router multicast)和区域本地组播(realm-local multicast)。
加入Thread网络的每个设备都将分配一个16位短地址,如[IEEE 802.15.4]中所规定。对于路由器,该地址使用地址字段中的较高位分配,低位设置为0,表示路由器地址。然后,对于子设备使用其父设备的高位和适当的低位来为其地址分配一个16位的短地址。这允许Thread网络中的任何其他设备通过使用其地址字段的高位来了解子设备的路由位置。
图2说明了Thread短地址。
所有设备使用[RFC 4944]和[RFC 6282]中定义的6LoWPAN。
在Thread网络中使用头部压缩(Header compression),设备传输消息尽可能多地压缩IPv6报头,以最小化发送的数据包的大小。
支持网格包头(mesh header),用于更有效地压缩网格内的消息,以及针对如“路由和网络连接”部分中所述的链路层转发(link layer forwarding)。网格标头(mesh header)还允许消息的端到端分段(end-to-end fragmentation),而不是[RFC 4944]中指定的逐跳分段(hop by hop fragmentation)。Thread协议栈使用路由选择配置(route-over configuration)。
这些设备不支持[RFC 6775]中规定的邻居发现(neighbor discovery),因为DHCPv6用于向路由器分配地址。终端设备和REED由他们的路由器父节点分配短地址。然后,该短地址用于配置用于网络内通信的网格(Mesh)本地ULA。
有关6LoWPAN使用和配置的更多详细信息,请参见“6LoWPAN的Thread用法(Thread Usage of 6LoWPAN)”白皮书。Thread规范的第3章详细说明了使用的具体6LoWPAN配置。
设备支持ICMPv6(Internet Control Message Protocol version 6,Internet控制消息协议版本6)协议[RFC 4443]和ICMPv6错误消息,以及回显请求(echo request)和回显回复消息(echo reply messages)。
Thread协议栈支持在[RFC 768]中定义的UDP(用户数据报协议),用于设备之间的消息传递。
Thread协议栈支持Thread网络中所有路由器之间的全网格连接(full mesh connectivity)。
实际拓扑基于Thread网络中路由器的数量。如果只有一个路由器或边界路由器,则形成具有单个路由器的基本星形拓扑。如果有多个路由器,则自动形成网格(Mesh)拓扑。图3说明了Thread网络的基本拓扑结构和设备类型。
网格网络(Mesh Networks)通过允许射频转发其他射频的消息,使射频系统更可靠。例如,如果节点不能直接向另一个节点发送消息,则网格网络(Mesh Networks)通过一个或多个中间节点转发消息。如“路由和网络连接”一节中所讨论的,Thread网络的性质使得所有路由器节点彼此之间保持路由和连接,因此网格不断维护和连接。Thread网络中通常有最多32个活动路由器的限制。但是,64个路由器地址用于允许回收路由器地址。
在网格网络(Mesh Networks)中,常眠终端设备或REED不会为其他设备路由。这些设备将消息发送到作为路由器的父设备。该父路由器处理其子设备的路由操作。
Thread网络通常最多有32个活动路由器,它们使用基于设备路由表的消息的下一跳路由(next-hop routing)。设备路由表由协议栈维护,以确保所有路由器都具有Thread网络中任何其他路由器的连接和最新路径。使用RIP(Routing Information Protocol,路由信息协议)算法(来自[RFC 1058]和[RFC 2080]的算法,但不采用其特定的消息格式)。所有路由器与其他路由器使用MLE(Mesh Link Establishment),以压缩格式交换其到Thread网络中的其他路由器的路由成本(cost of routing)。
注意:从IP的角度来看,Thread网络支持路由器和主机。主机是常眠终端设备或REED。
MLE消息(请参阅“Thread规范”第4章“消息链路建立(Message Link Establishment)” 中针对Thread进行的扩展[draft-kelsey-intarea-mesh-link-establishment-06]) 用于建立和配置安全射频链路,检测邻近设备,以及维护Thread网络中设备之间的路由成本。使用单跳链路本地单播(single-hop link local unicasts)和路由器之间多播(multicasts between Routers)来传输MLE消息。
随着拓扑和物理环境的变化,MLE消息用于识别,配置和保护邻近设备的链路。MLE还用于分发跨Thread网络共享的配置值,如通道(channel)和PAN(Personal Area Network,个人区域网络)ID。这些消息可以由MPL(Multicast Protocol for Low power and Lossy Networks,低功耗和有损网络的多播协议)指定的简单洪泛转发(forwarded with simple flooding)。(有关详细信息,请参阅[draft-ietf-roll-trickle-mcast-09])。
在建立两个设备之间的路由成本时,MLE消息还确保考虑了非对称链路成本(asymmetric link costs)。802.15.4网络中的非对称链路成本(asymmetric link costs)很常见。为了确保双向通信是可靠的,考虑双向链路的成本是很重要的。
按需路由发现(On-demand route discovery)通常用于低功耗802.15.4网络。然而,由于路由发现请求洪泛网络(route discovery requests flooding the network),按需路由发现(on-demand route discovery)在网络开销和带宽方面是昂贵的。
在Thread网络中,所有路由器定期交换包含到所有邻居路由器链路成本信息(link cost information to all neighbor Routers)的单跳MLE广告包(single-hop MLE advertisement packets),以及到Thread网络中所有其他路由器的路径开销(path costs to all other Routers)。通过这些定期的本地更新,所有路由器都具有Thread网络中任何其他路由器的最新路径开销信息,因此不需要按需路由发现。如果路由不再可用,路由器可以在到达目的地的下一个最合适的路由上进行选择。这种自愈路由机制允许路由器快速检测其他路由器是否已经脱离Thread网络,并计算最佳路径以维护与Thread网络中所有其他设备的连接。
每个方向的链路质量(link quality in each direction)基于来自该邻近设备的传入消息的链路成本(link cost on incoming messages from that neighboring device)。此传入链路成本(incoming link cost)映射到从0到3的链路质量(link quality)。值为0表示未知成本。链路成本(link cost is a measure of RSSI)是接收到的消息高于接收等级的RSSI(接收信号强度指示)的度量。
表1总结了链路质量和链路成本。
图4示出了Thread网络上的各种链路成本的示例。
Thread网络中任何其他节点的路径开销就是到达该节点的链路成本的最小值。路由器监控这些成本,即使网络的射频链路质量或拓扑变化,并通过使用周期性MLE广告消息在Thread网络传播新的成本。路由成本基于两个设备之间的双向链路质量。
为了说明一个简化的例子,想象一下预先委托的网络(pre-commissioned network),其中共享安全材料,所有的设备同时启动。每个路由器将周期性地发送初始填充的到单跳邻居成本的广告。在内部,每个路由器将存储未在广告中发送的下一跳信息(next hop information)。
前几个广告的路径成本等于链路成本,因为已知的唯一路由器是立即邻居,如图5所示。
但是,随着路由器开始收听来自邻居的广告,其中包含两跳或更多跳的其他路由器的成本,它们的表填充了多跳路径成本,然后传播得更远,直到最终在所有路由器之间存在如图6和图7所示的连接信息网络。
当路由器从邻居接收到新的MLE广告时,它或者已经具有该设备的邻居表项,或者添加一个。MLE广告包含来自邻居的进入成本(incoming cost from the neighbor),因此在路由器的邻居表中更新(updated in the Router’s neighbor table)。MLE广告还包含其他路由器的更新的路由信息??(updated routing information for other Routers),并且该信息在设备路由表中更新(updated in the device routing table)。
通过查看子设备的地址的高位来确定父路由器地址(Parent Router address),可以实现到子设备的路由。一旦设备知道父路由器,它就具有该设备的路径开销信息和下一跳路由信息(path cost information and next-hop routing information)。
活动路由器的数量仅限于可以包含在单个802.15.4数据包中的路由和成本信息的数量。此限制目前为32个路由器,但提供了64个活动路由器地址以允许老化掉路由器地址(aging out of Router addresses)。
设备使用IP路由转发数据包(IP routing to forward packets)。设备路由表(device routing table)填充有路由器的网格本地ULA地址的压缩形式和适当的下一跳(compressed form of a mesh local ULA address for Routers and the appropriate next hop)。
距离向量路由(Distance vector routing)用于获取到Thread网络上路由器地址的路由(get routes to Router addresses)。当在Thread网络上进行路由时,该16位地址的高6位定义了目标路由器的路由器地址。如果目的地址的低位为0,则路由器为最终目的地址。否则,目的路由器负责根据16位目的地址的较低位转发到最终目的地。
对于超出Thread网络的路由,边界路由器通知Leader其所服务的特定前缀(particular prefix(es) it serves),并且该信息作为MLE数据包中的Thread网络数据分发(distributed as Thread Network data within the MLE packets)。Thread网络数据包括:前缀数据(prefix data),它是前缀本身,6LoWPAN上下文(6LoWPAN context),边界路由器(Border Routers)和该前缀的DHCPv6服务器(DHCPv6 server for that prefix)。如果设备要使用该前缀配置IPv6地址,则使用SLAAC(Stateless Address Autoconfiguration,无状态地址自动配置)或联系相应的DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)服务器。Thread网络数据还包括路由服务器列表(a list of routing servers),它们是默认的边界路由器的路由器地址。
Leader被指定做出决策,选择REED成为路由器或允许路由器降级为REED。Leader也分配和管理路由器地址。然而,此路由Leader中包含的所有信息都存在于其他路由器中,并且如果路由Leader变得无法访问,则另一个路由器将自主被选择并作为Leader接管,而无需用户干预。
虽然在Thread协议栈中使用UDP消息传递,但仍然需要可靠的消息传递。这是使用一系列轻量级机制完成的,如下所示:
加入设备(joining device)必须经历各个阶段才能参与Thread网络:
所有加入都是Thread网络中用户启动的。一旦加入,设备就可以完全参与Thread网络,并可以与Thread网络内外的其他设备和服务交换应用层信息。
加入设备(joining device)必须发现Thread网络,并与路由器建立联系(establish contact with a Router)以进行调试(commissioning)。加入设备扫描所有信道(scans all channels),在每个信道上发出信标请求(issues a beacon request),并等待信标响应(waits for beacon responses)。信标包含一个有效载荷,包括网络SSID(Service Set Identifier,服务集标识符)和允许加入信标的许可证(a permit joining beacon),指示Thread网络是否正在接受新的成员。一旦设备发现Thread网络,它将使用MLE消息来建立一个相邻的路由器(establish a neighboring Router),通过它可以执行调试(perform commissioning)。
如果设备已经获得了调试信息(obtained commissioning information),因为它已经有足够的信息直接附加到Thread网络,则不需要发现。
Thread提供两种调试方法:
注意:仅在通过信标有效载荷中的许可证加入标志(joining solely via the permit joining flag in the beacon payload)的典型802.15.4加入方法不在Thread网络中使用。这种方法最常用于没有用户界面或到设备的带外频道的按钮类型加入(push button type joining)。在有多个网络可用的情况下,该方法可能存在设备转向(device steering)问题,并且也可能存在安全问题。
具有调试信息(commissioning information)的加入设备(joining device)与父路由器联系,然后通过父路由器交换MLE链路配置消息(exchanging MLE link configuration messages)附加到Thread网络。设备作为终端设备(end device)或REED附加到Thread网络,并由父路由器分配16位短地址,如图8所示。
一旦REED已经附加到Thread网络,它可能会发出一个地址请求(issue an address request)成为一个路由器,然后由Leader分配一个路由器地址。
一旦设备连接到Thread网络,就需要有各种各样的信息来保持其在网络中的参与。MLE提供服务以在整个网络中分发网络数据,并在邻居之间交换链路成本(link costs)和安全帧计数器(security frame counters)。
MLE消息分发或交换以下信息:
注意 :MLE消息是被加密的,除非是在发现时,加入设备获得所需的安全资料过程中。
DHCPv6 [RFC 3315]是一种基于UDP的客户端 - 服务器协议,用于管理网络中设备的配置。DHCPv6使用UDP从DHCP服务器请求数据。
边界路由器上的DHCPv6服务用于配置:
所有设备都支持ICMPv6错误消息,以及回显请求( echo request)和回显回应消息( echo reply messages)。
设备上的应用层可以访问一组设备管理和诊断信息,这些信息可以在本地使用或收集并发送到其他管理设备。
Thread协议栈从802.15.4 MAC层使用的信息包括:
Thread协议栈从网络层使用的信息包括:
由于各种原因,在现场操作的设备可能会意外重置或故障重置。已重置的设备需要重新启动网络操作,无需用户干预。为此,需要将一组信息存储在非易失性存储中。这包括:
短距离无线通信技术有哪些?各自的特点是什么
短距离无线通信技术举例和优点介绍如下:
1、红外线(Infrared)
红外线可分为直接式红外线(Direct-BeamIR)、散射式红外线(DiffuseIR)以及全向性红外线(OminidirectionalIR)。
由于红外线是光的一种,而光不能穿透任何不透明的物体,因此在直接式红外线连接模式下传输资料时,二个互通的点必须是在相互可看见的同一线上。
而不能有任何阻隔;散射式红外线连接模式则不需在同一线上,但必须是在同一个封闭的空间内;全向性红外线则是利用一个红外线的基地台,将分散在基地台四周的发射器所发射的红外线集中起来。
2、IEEE802.11
IEEE802.11适用在区域环境下,如需要自由行动支援的办公室,能使用无线传输节省办公室成本;只需要架设一个基地台,以及在这个区域内的电子产品都安装网路卡,利用IEEE802.11无线传输技术,在没有任何连接线的情况下,资料在室内传输距离可达100公尺(无障碍可达300公尺)。
3、蓝牙(Bluetooth)
蓝牙是一种短距离、低功率、低成本的无线通讯标准,以取代红外线传输距离过短、不具穿透性等问题。蓝牙的发展计划中,是将其定位为低功率、涵盖范围小的跳频RF系统。
其设计适用於连结电脑与电脑、电脑与周边以及电脑与其他行动数据装置,如行动电话、呼叫器、PDA等。由於蓝牙模组可以轻易植入任何电子产品,因此使用者通过任何蓝芽装置即可与这些产品沟通。
4、HomeRF
HomeRF建构在SWAP(ShareWirelessAccessprotocol)技术上,主要应用在家庭网路。其不只能进行资料的传送,更整合了语音传输能力,可将电脑网路与电话网路结合。
提供一个更完整的解决方案。目前在无线网路环境中,HomeRF较蓝芽的传输距离长、传输资料量也较多,因此较适合影音传输之应用。
5、LIFI
LiFi是用可见光来实现无线通信,即利用电信号控制发光二极管(LED)发出的肉眼看不到的高速闪烁信号来传输信息。且不会产生电磁干扰。
参考资料:百度百科-短距无线传输技术
参考资料:百度百科-LIFI
常用的无线短距离通信技术主要有:华为Hlilink协议、WIFI(IEEE802.11协议)、Mesh、蓝牙、ZigBee/802.15.4协议、Thread/802.15.4协议、Z—Wave、NFC、UWB、LiFi等10大类。主要特点:
华为Hlilink协议,兼容性好,能自动发现设备并一键链接。
WIFI(IEEE802.11协议),是无线局域网中的一个标准,覆盖范围广,传输速率快,但安全性不好,稳定性差,功耗略高,组网能力差。
Mesh,网络部署快,稳定性好,但有一定延迟性,网络容量有限。
蓝牙,速率快,低功耗,安全性高,但网络节点少,不适合多点布控。
ZigBee/802.15.4协议,安全性高,功耗低,组网能力强,容量大,但成本高,抗干扰性差,通信距离短。
Thread/802.15.4协议,传输安全,可靠性高,兼容性好,未来发展潜力很大。
Z—Wave协议,结构简单,低速率,低功耗,低成本,但标准不开放。
NFC,近场通信,与蓝牙技术类似,但传输速率和距离没有蓝牙快和远,功耗和成本低,保密性好,适用于移动支付和消费类电子。
UWB,抗干扰性强,速率高,带宽大,功率小,功耗低,但目前标准化争议大,发展也因此收到限制。
LiFi,是光保真技术,不会产生电磁干扰。
根据所了解到的短距离无线通信技术主要有:华为Hlilink协议、WIFI(IEEE802.11协议)、Mesh、蓝牙、ZigBee/802.15.4协议、Thread/802.15.4协议、Z—Wave、NFC、UWB等等。
短距离无线通信技术主要有:华为Hlilink协议、WIFI(IEEE802.11协议)、Mesh、蓝牙、ZigBee/802.15.4协议、Thread/802.15.4协议、Z—Wave、NFC、UWB、LiFi等10大类。
各自特点如下:
1、华为Hlilink协议
兼容性好,能自动发现设备并一键链接。
2、WIFI(IEEE802.11协议)
IEEE802.11适用在区域环境下,如需要自由行动支援的办公室,能使用无线传输节省办公室成本;只需要架设一个基地台,以及在这个区域内的电子产品都安装网路卡,利用IEEE802.11无线传输技术,在没有任何连接线的情况下,资料在室内传输距离可达100公尺(无障碍可达300公尺)。
3、Mesh
网络部署快,稳定性好,但有一定延迟性,网络容量有限。
4、蓝牙
蓝牙是一种短距离、低功率、低成本的无线通讯标准,以取代红外线传输距离过短、不具穿透性等问题。蓝牙的发展计划中,是将其定位为低功率、涵盖范围小的跳频RF系统,其设计适用於连结电脑与电脑、电脑与周边以及电脑与其他行动数据装置,如行动电话、呼叫器、PDA等。
5、ZigBee/802.15.4协议
安全性高,功耗低,组网能力强,容量大,但成本高,抗干扰性差,通信距离短。
6、Thread/802.15.4协议
传输安全,可靠性高,兼容性好,未来发展潜力很大。
7、Z—Wave协议
结构简单,低速率,低功耗,低成本,但标准不开放。
8、NFC
近场通信,与蓝牙技术类似,但传输速率和距离没有蓝牙快和远,功耗和成本低,保密性好,适用于移动支付和消费类电子。
9、UWB
抗干扰性强,速率高,带宽大,功率小,功耗低,但目前标准化争议大,发展也因此收到限制。
10、LiFi
LiFi是用可见光来实现无线通信,即利用电信号控制发光二极管(LED)发出的肉眼看不到的高速闪烁信号来传输信息。且不会产生电磁干扰。
参考资料来源:百度百科-短距无线传输技术
物联网的关键技术有哪些
物联网的关键技术有低功耗广域网(LPWAN)、蜂窝移动(3G/4G/5G)、Zigbee和其他网状协议等。
一、低功耗广域网(LPWAN)
低功耗广域网是物联网中的新现象。该系列技术通过使用小型的、廉价的电池提供长达数年的远程通信服务,旨在支持遍布工业、商业和校园的大规模物联网应用。
低功耗广域网几乎可以连接所有类型的物联网传感器,促进了从远程监控、智能计量和工人安全到建筑物控制和设施管理的众多应用。尽管如此,低功耗广域网只能以低速率发送小块数据,因此更适合于不需要高带宽且不具有时间敏感性的用例。
此外,同样,并非所有低功耗广域网都是一样的。如今,存在许可低功耗广域网技术(NB-IoT、LTE-M)和未经许可低功耗广域网技术(例如MIOTY、LoRa、Sigfox等)。这些技术在关键网络因素中的表现程度各不相同。
二、蜂窝移动(3G/4G/5G)
蜂窝移动网络在消费者市场中根深蒂固,提供了可靠的宽带通信,并支持各种语音呼叫和流视频应用。不利的一面是,它们会带来非常高的运营成本和电力需求。
虽然蜂窝移动网络不适用于大多数由电池供电的传感器物联网应用,但它们却非常适合特定的使用情形,例如交通和物流中的联网汽车或车队管理。此外,像车载信息娱乐系统、交通路线、高级驾驶辅助系统(ADAS)以及车队远程信息处理和跟踪服务都可以依靠无处不在的高带宽蜂窝移动网络。
具有高速和超低延迟的下一代移动网络5G将成为自动驾驶汽车和增强现实(VR)的未来。预计5G还将实现用于公共安全的实时视频监控、用于互联健康的医疗数据集的实时移动传输,以及一些对时间敏感的工业自动化应用。
三、Zigbee和其他网状协议
Zigbee是一种短距离、低功耗无线技术(IEEE 802.15.4),通常部署在网状拓扑中,以通过在多个传感器节点上中继传感器数据来扩展覆盖范围。与低功耗广域网相比,zigbee提供了更高的数据速率,但同时由于网格配置而降低了能耗效率。
由于它们的物理距离短(《100m),Zigbee和类似的网状协议(例如Z-Wave、Thread等)最适合节点分布均匀且非常接近的中程物联网应用。通常,Zigbee是WI-FI的完美补充,适用于智能照明、暖通空调控制、安全和能源管理等各种家庭自动化应用。
java多线程开发的同步机制有哪些
一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在 java里边就是拿到某个同步对象的锁(一个对象只有一把锁); 如果这个时候同步对象的锁被其他线程拿走了,他(这个线程)就只能等了(线程阻塞在锁池 等待队列中)。 取到锁后,他就开始执行同步代码(被synchronized修饰的代码);线程执行完同步代码后马上就把锁还给同步对象,其他在锁池中 等待的某个线程就可以拿到锁执行同步代码了。这样就保证了同步代码在统一时刻只有一个线程在执行。
众所周知,在Java多线程编程中,一个非常重要的方面就是线程的同步问题。
关于线程的同步,一般有以下解决方法:
1. 在需要同步的方法的方法签名中加入synchronized关键字。
2. 使用synchronized块对需要进行同步的代码段进行同步。
3. 使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象。
另外,为了解决多个线程对同一变量进行访问时可能发生的安全性问题,我们不仅可以采用同步机制,更可以通过JDK 1.2中加入的ThreadLocal来保证更好的并发性。
Java的线程机制 摘 要: 多线程机制是Java的重要技术,阐述了线程和进程的差别;Java中线程4个状态之间的转换;并结合例子说明了两种创建线程的方法。 线程是指程序中能顺序执行的一个序列。一个线程只有一个入口点? 但可能有几个出口点? 不过,每个时刻的执行点总是只有一个。线程是不能独立运行的程序,而只是某个整体程序内部的一个顺序执行流。 多线程是Java的一个重要特点。如果一个程序是单线程的,那么,任何时刻都只有一个执行点。这种单线程执行方法使系统运行效率低,而且,由于必须依靠中断来处理输入/输出。所以,当出现频繁输入/输出或者有优先级较低的中断请求时,实时性就变得很差。多线程系统可以避免这个缺点。所谓多线程,就是通过系统的调度使几个具有不同功能的程序流即线程同时并行地运行。 在单处理器计算机系统中,实际上是不可能使多个线程真正并行运行的,而要通过系统用极短的时间、极快的速度对多个线程进行切换,宏观上形成多个线程并发执行的效果。 1 线程和进程机制上的差别 线程和进程很相象,它们都是程序的一个顺序执行序列,但两者又有区别。进程是一个实体,每个进程有自己独立的状态,并有自己的专用数据段,创建进程时, 必须建立和复制其专用数据段,线程则互相共享数据段。同一个程序中的所有线程只有一个数据段, 所以, 创建线程时不必重新建立和复制数据段。由于数据段建立和复制这方面的差异,使线程的建立和线程间的切换速度大大优于进程,另一方面,线程又具备进程的大多数优点。 假设银行系统办理存款和取款手续,将帐本看成数据段。如果按进程这种机制,那么,当储户去存/取款时,银行应先把帐本复制一遍,为储户建立一个独立的帐本再结算。如果按线程机制, 那么,银行里所有的出纳员都用同一个帐本,储户来办存/取款时,也从这个帐本直接结算。用线程机制省去了数据段复制这一步显然是线程独具的特点。 由于多个线程共享一个数据段,所以,也出现了数据访问过程的互斥和同步问题,这使系统管理功能变得相对复杂。 总的来说,一个多线程系统在提高系统的输入/输出速度、有效利用系统资源、改善计算机通信功能以及发挥多处理器硬件功能方面显示了很大优势。因此,一些最新的操作系统如Windows95、Windows98、Windows NT等都提供了对多线程的支持。但是,在多线程操作系统下设计多线程的程序仍然是一个比较复杂和困难的工作。由于需要解决对数据段的共享,所以,原则上应该从程序设计角度采用加锁和释放措施,稍有不慎,便会使系统产生管理上的混乱。 而Java从语言一级提供对多线程的支持,这样,可由语言和运行系统联合提供对共享数据段的管理功能和同步机制,使得多线程并行程序设计相对比较容易。 2 Java线程的生命周期 每个线程都是和生命周期相联系的,一个生命周期含有多个状态,这些状态间可以互相转化。 Java的线程的生命周期可以分为4个状态;创建(new)状态;可运行(runnable)状态;不执行(notrunnable)状态;消亡(dead)状态。 创建状态是指创建一个线程对应的对象的过程,Java系统中,些对象都是从Java.lang包内一个称为Thread的类用关键字new创建的。刚创建的线程不能执行,必须向系统进行注册、分配必要的资源后才能进入可运行状态,这个步骤是由start操作完成的,而处于可运行状态的线程也未必一定处于运行中,它有可能由于外部的I/O请求而处于不运行状态。进入消亡状态后,此线程就不再存在了。 一个线程创建之后,总是处于其生命周期的4个状态之一中,线程的状态表明此线程当前正在进行的活动,而线程的状态是可以通过程序来进行控制的,就是说,可以对线程进行操作来改变状态。 这些操作包括启动(start)、终止(stop)、睡眠(sleep)、挂起(suspend)、恢复(resume)、等待(wait)和通知(notify)。每一个操作都对应了一个方法? 这些方法是由软件包Java.lang提供的。通过各种操作,线程的4个状态之间可按图1所示进行转换。 2.1 创建(new)状态 如果创建了一个线程而没有启动它,那么,此线程就处于创建状态。比如,下述语句执行以后,使系统有了一个处于创建状态的线程myThread:? Thread myThread=new MyThreadClass(); 其中,MyThreadClass()是Thread的子类,而Thread是由Java系统的Java.lang软件包提供的。处于创建状态的线程还没有获得应有的资源,所以,这是一个空的线程,线程只有通过启动后,系统才会为它分配资源。对处于创建状态的线程可以进行两种操作: 一是启动(start)操作,使其进入可运行状态;二是终止(stop)操作,使其进入消亡状态。如果进入到消亡状态,那么,此后这个线程就不能进入其它状态,也就是说,它不复存在了。 start方法是对应启动操作的方法,其具体功能是为线程分配必要的系统资源,将线程设置为可运行状态,从而可以使系统调度这个线程。 2.2 可运行(runnable)状态 如果对一个处于创建状态的线程进行启动操作,则此线程便进入可运行状态。比如,用下列语句? myThread.start();? ?? 则使线程myThread进入可运行状态。上述语句实质上是调用了线程体即run()方法,注意,run()方法包含在myThread线程中,也就是先由java.lang包的Thread类将run()方法传递给子类MyThreadClass(),再通过创建线程由子类MyThreadClass,传递给线程myThread。 线程处于可运行状态只说明它具备了运行条件,但可运行状态并不一定是运行状态,因为在单处理器系统中运行多线程程序,实际上在一个时间点只有一个线程在运行,而系统中往往有多个线程同时处于可运行状态,系统通过快速切换和调度使所有可运行线程共享处理器,造成宏观上的多线程并发运行。可见,一个线程是否处于运行状, 除了必须处于可运行状态外,还取决于系统的调度。 在可运行状态可以进行多种操作,最通常的是从run()方法正常退出而使线程结束,进入消亡状态。 此, 还可以有如下操作? 挂起操作,通过调用suspend方法来实现; 睡眠操作,通过调用sleep方法来实现; 等待操作,通过调用wait方法来实现; 退让操作,通过调用yield方法来实现; 终止操作,通过调用stop方法来实现。 前面三种操作都会使一个处于可运行状态的线程进入不可运行状态。比如,仍以myThread线程为例,当其处于可运行状态后,再用如下语句? myThread.sleep (5000); 则调用sleep方法使myThread线程睡眠5s(5000ms)。这5s内,此线程不能被系统调度运行,只有过5s后,myThread线程才会醒来并自动回到可运行状态。 如果一个线程被执行挂起操作而转到不可运行状态,则必须通过调用恢复(resume)操作,才能使这个线程再回到可运行状态。 退让操作是使某个线程把CPU控制权提前转交给同级优先权的其他线程。 对可运行状态的线程也可以通过调用stop方法使其进入消亡状态。 2.3 不可运行(not runnable)状态 不可运行状态都是由可运行状态转变来的。一个处于可运行状态的线程,如果遇到挂起(suspend)操作、睡眠(sleep)操作或者等待(wait)操作,就会进入不可运行状态。 另外,如果一个线程是和I/O操作有关的,那么,在执行I/O指令时,由于外设速度远远低于处理器速度而使线程受到阻, 从而进入不可运行状态,只有外设完成输入/输出之后,才会自动回到可运行状态。线程进入不可运行状态后,还可以再回到可运行状态,通常有三种途径使其恢复到可运行状态。 一是自动恢复。通过睡眠(sleep)操作进入不可运行状态的线程会在过了指定睡眠时间以后自动恢复到可运行状态,由于I/O阻塞而进入不可运行状态的线程在外设完成I/O操作后,自动恢复到可运行状态。 二是用恢复(resume)方法使其恢复。如果一个线程由于挂起(suspend)操作而从可运行状态进入不可运行状态,那么,必须用恢复(resume)操作使其再恢复到可运行状态。 三是用通知(notify或notifyAll)方法使其恢复。如果一个处于可运行状态的线程由于等待(wait)操作而转入不可运行状态,那么,必须通过调用notify方法或notifyAll方法才能使其恢复到可运行状态,采用等待操作往往是由于线程需要等待某个条件变量,当获得此条件变量后,便可由notify或ontifyAll方法使线程恢复到可运行状态。 恢复到可运行状态的每一种途径都是有针对性的,不能交叉。比如,对由于阻塞而进入不可运行状态的线程采用恢复操作将是无效的。 在不可运行状态,也可由终止(stop)操作使其进入消亡状态。 2.4 消亡(dead)状态 一个线程可以由其他任何一个状态通过终止(stop)操作而进入消亡状态。 线程一旦进入消亡状态,那它就不再存在了,所以也不可能再转到其它状态。 通常,在一个应用程序运行时,如果通过其它外部命令终止当前应用程序,那么就会调用(stop)方法终止线程。但是,最正常、最常见的途径是由于线程在可运行状态正常完成自身的任务而″寿终正寝″,从而进入消亡状态,这个完成任务的动作是由run方法实现的。 3 Java线程的两种创建途径 一种途径是通过对Thread的继承来派生一个子类,再由此子类生成一个对象来实现线程的创建,这是比较简单直接的办法。Thread类包含在系统API提供的8个软件包之一Java.lang中,Thread类中包含了很多与线程有关的方, 其中,一个名为run的方法就是用来实现线程行为的。比如:? 1 import java.lang.*? //引用lang包 2 class Mango exteds Thread { 3 public void run() { 4 ...... 5 ?} 6 ?} 上述程序段中,第1行语句引用软件包lang,这样做是为了给编译器一个信息,从而使后面程序中有关lang包中的方法可直接用方法名,而不必带前缀“Java.lang”。第2行语句是从lang包Thread派生一个子类Mango, 而这个子类中提供了run方法的实现,这样,运行时,将由子类Mango 的 run方法置换父类Thread的run方法。 不过这一步还没有创建线, 必须由子类生成一个对象,并且进行启动操作,这样才能得到一个处于可运行状态的线程。生成对象其实就是完成线程的创建,而启动是对已创建的线程进行操作。具体语句如下:? Mango t=new Mango(); ?? t.start(); ?? 上面先用关键字new使线程进入创建状态,又调用start()方法使线程进入可运行状态。注意,start()方法是由Thread继承给子类Mango、然后又在生成对象时由对象t从类Mango得到的。 另一种途径是通过一个类去继承接口runnable来实现线程的创建? 而这个类必须提供runnable接口中定义的方法run()的实现。runnable是Java.lang包中的一个接口,在runnable接口中,只定义了一个抽象方法run()。所以,如用这种途径来创建线程,则应先由一个类连接接口runnable,并且提供run()方法的实现。比如,下面的程序段实现了与接口的连接。 1 public class xyz implements Runnable{ 2 int i; ? 3 public voed run(){ 4 while (true){? ? 5 System.out.println("Hello"+i++); 6 ? } 7 ? } 8 ? } 然后再创建一个线程? runnable r=new xyz(); ?? Thread t=new Thread(r); 这种途径创建线程比第一种途径灵活。当一个类既需要继承一个父类又要由此创建一个线程时,由于Java不支持多重继承,这样,用第一种途径将行不通,因为,按此思路创建线程也是以继承的方法实现的。 于是,就需要一个类既继承Thread类,又继承另一个父类。但用接口方法却能实现这个目标。 4 线程的启动和终止 Thread的start()方法对应于启动操作,它完成两方面的功能:一方面是为线程分配必要的资源,使线程处于可运行状态,另一方面是调用线程的run()方法置换Thread的中run()方法或者置换runnable中的run()方法来运行线程。 使用start()方法的语句很简单,即: ThreadName.start(); 下面的程序段先创建并启动线程myThread, 然后使用sleep()方法让其睡眠20000ms即20s,使其处于不可运行状态,过20s后,线程又自动恢复到可运行状态。 Thread MyThread=new MyThreadClass(); MyThread.start();? ?? try{ ? MyThread.sleep(20000); ?} catch(InterrujptedException e){ } ?
Java同步
标签: 分类:
一、关键字:
thread(线程)、thread-safe(线程安全)、intercurrent(并发的)
synchronized(同步的)、asynchronized(异步的)、
volatile(易变的)、atomic(原子的)、share(共享)
二、总结背景:
一次读写共享文件编写,嚯,好家伙,竟然揪出这些零碎而又是一路的知识点。于是乎,Google和翻阅了《Java参考大全》、《Effective Java Second Edition》,特此总结一下供日后工作学习参考。
三、概念:
1、 什么时候必须同步?什么叫同步?如何同步?
要跨线程维护正确的可见性,只要在几个线程之间共享非 final 变量,就必须使用 synchronized(或 volatile)以确保一个线程可以看见另一个线程做的更改。
为了在线程之间进行可靠的通信,也为了互斥访问,同步是必须的。这归因于java语言规范的内存模型,它规定了:一个线程所做的变化何时以及如何变成对其它线程可见。
因为多线程将异步行为引进程序,所以在需要同步时,必须有一种方法强制进行。例如:如果2个线程想要通信并且要共享一个复杂的数据结构,如链表,此时需要
确保它们互不冲突,也就是必须阻止B线程在A线程读数据的过程中向链表里面写数据(A获得了锁,B必须等A释放了该锁)。
为了达到这个目的,java在一个旧的的进程同步模型——监控器(Monitor)的基础上实现了一个巧妙的方案:监控器是一个控制机制,可以认为是一个
很小的、只能容纳一个线程的盒子,一旦一个线程进入监控器,其它的线程必须等待,直到那个线程退出监控为止。通过这种方式,一个监控器可以保证共享资源在
同一时刻只可被一个线程使用。这种方式称之为同步。(一旦一个线程进入一个实例的任何同步方法,别的线程将不能进入该同一实例的其它同步方法,但是该实例
的非同步方法仍然能够被调用)。
错误的理解:同步嘛,就是几个线程可以同时进行访问。
同步和多线程关系:没多线程环境就不需要同步;有多线程环境也不一定需要同步。
锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility)。
互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据。
可见性要更加复杂一些,documents它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 —— 如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前的值或不一致的值,这将引发许多严重问题
小结:为了防止多个线程并发对同一数据的修改,所以需要同步,否则会造成数据不一致(就是所谓的:线程安全。如java集合框架中Hashtable和
Vector是线程安全的。我们的大部分程序都不是线程安全的,因为没有进行同步,而且我们没有必要,因为大部分情况根本没有多线程环境)。
2、 什么叫原子的(原子操作)?
Java原子操作是指:不会被打断地的操作。(就是做到互斥 和可见性?!)
那难道原子操作就可以真的达到线程安全同步效果了吗?实际上有一些原子操作不一定是线程安全的。
那么,原子操作在什么情况下不是线程安全的呢?也许是这个原因导致的:java线程允许线程在自己的内存区保存变量的副本。允许线程使用本地的私有拷贝进
行工作而非每次都使用主存的值是为了提高性能(本人愚见:虽然原子操作是线程安全的,可各线程在得到变量(读操作)后,就是各自玩
弄自己的副本了,更新操作(写操作)因未写入主存中,导致其它线程不可见)。
那该如何解决呢?因此需要通过java同步机制。
在java中,32位或者更少位数的赋值是原子的。在一个32位的硬件平台上,除了double和long型的其它原始类型通常都
是使用32位进行表示,而double和long通常使用64位表示。另外,对象引用使用本机指针实现,通常也是32位的。对这些32位的类型的操作是原
子的。
这些原始类型通常使用32位或者64位表示,这又引入了另一个小小的神话:原始类型的大小是由语言保证的。这是不对的。java语言保证的是原始类型的表
数范围而非JVM中的存储大小。因此,int型总是有相同的表数范围。在一个JVM上可能使用32位实现,而在另一个JVM上可能是64位的。在此再次强
调:在所有平台上被保证的是表数范围,32位以及更小的值的操作是原子的。
3、 不要搞混了:同步、异步
举个例子:普通B/S模式(同步)AJAX技术(异步)
同步:提交请求->等待服务器处理->处理完返回 这个期间客户端浏览器不能干任何事
异步:请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕
可见,彼“同步”非此“同步”——我们说的java中的那个共享数据同步(synchronized)
一个同步的对象是指行为(动作),一个是同步的对象是指物质(共享数据)。
4、 Java同步机制有4种实现方式:(部分引用网上资源)
① ThreadLocal ② synchronized( ) ③ wait() 与 notify() ④ volatile
目的:都是为了解决多线程中的对同一变量的访问冲突
ThreadLocal
ThreadLocal 保证不同线程拥有不同实例,相同线程一定拥有相同的实例,即为每一个使用该变量的线程提供一个该变量值的副本,每一个线程都可以独立改变自己的副本,而不是与其它线程的副本冲突。
优势:提供了线程安全的共享对象
与其它同步机制的区别:同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信;而 ThreadLocal 是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源,这样当然不需要多个线程进行同步了。
volatile
volatile 修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。
优势:这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
缘由:Java
语言规范中指出,为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原
始值对比。这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。而 volatile
关键字就是提示 VM :对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
使用技巧:在两个或者更多的线程访问的成员变量上使用 volatile 。当要访问的变量已在 synchronized 代码块中,或者为常量时,不必使用。
线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B。只在某些动作时才进行A和B的同步,因此存在A和B不一致
的情况。volatile就是用来避免这种情况的。
volatile告诉jvm,它所修饰的变量不保留拷贝,直接访问主内存中的(读操作多时使用较好;线程间需要通信,本条做不到)
Volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile
变量的最新值。Volatile
变量可用于提供线程安全,但是只能应用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后值
之间没有约束。
您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
对变量的写操作不依赖于当前值;该变量没有包含在具有其他变量的不变式中。
sleep() vs wait()
sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,把执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。
wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
(如果变量被声明为volatile,在每次访问时都会和主存一致;如果变量在同步方法或者同步块中被访问,当在方法或者块的入口处获得锁以及方法或者块退出时释放锁时变量被同步。)
c#报错,套接字接口协议端口只能使用一次,但是我不知道怎么释放端口号,重新绑定
listener.Start(); //开启监听while(true){ Socket newSocket = listener.AcceptSocket(); //接收到一个远端连接socket Thread newThread = new Thead(new ThreadStart(newSocket)); //把新socket送到新线程里去 newThread.Start();}
Tomcat基础(2)
Tomcat服务器的配置主要集中于tomcat/conf下的catalina.policy, catalina.properties,context.xml、server.xml、tomcat-users.xml、web.xml文件。
server.xml 是tomcat服务器的核心配置文件,包含了Tomcat的servlet容器(catalina)的所有配置。由于配置的属性特别多,我们在这里主要讲解其中的一部分重要配置。
Server是server.xml的根元素,用于创建一个Server实例,默认使用的实现类是org.apache.catalina.core.standardserver.
port:Tomcat监听的关闭服务器的端口。
shutdown:关闭服务器的指令字符串。
Server内嵌的子元素为Listener, GlobalNamingResources, Service.
默认配置的5个Listener的含义
GlobalNamingResources中定义了全局命名服务
该元素用于创建Service实例,默认使用org.apache.catalina.core.Standardservice,默认情况下,Tomcat仅指定了Service的名称,值为"Catalina",Service可以内嵌的元素为:Listener, Executor, connector, Engine ,其中Listener用于为Service添加生命周期监听器,Executor用于配置Service共享线程池,Connector用于配置Service包含的链接器,Engine用于配置Service中链接器对应的Servlet容器引擎。一个Server服务器,可以包含多个Service服务。
默认情况下Service并未添加共享线程池配置,如果我们想添加一个线程池,可以在下添加如下配置:
属性说明
属性含义
name线程池名称,用于Connector中指定。
nameprefix所创建的每个线程的名称前缀,一个单独的线程名称为namePrefix+threadNumber.
maxThreads池中最大线程数。
minSpareThreads活跃线程数,也就是核心池线程数,这些线程不会被销毁,会一直存在。
maxIdleTime线程空闲时间,超过该时间后,空闲线程会被销毁,默认值为6000 (1分钟) ,单位毫秒。
maxQueuesize在被执行前最大线程排队数目,默认为Int的最大值,也就是广义的无限。除非特殊情况,这个值不需要更改,否则会有请求不会被处理的情况发生。
prestartminSpareThreads启动线程池时是否启动minSpareThreads部分线程。默认值为false,即不启动。
threadPriority线程池中线程优先级,默认值为5,值从1到10。
className
线程池实现类,未指定情况下,默认实现类为org.apache.catalina.core.standardThreadExecutor,如果想使用自定义线程池首先需要实现? org.apache.catalina.Executor接口。
JDK工具jconsole.exe观察线程池被创建
如果不配置共享线程池,那么Catalina各组件在用到线程池时会独立创建。
Connector用于创建链接器实例。默认情况下, server.xml配置了两个链接器,一个支持HTTP协议,一个支持AJP协议。因此大多数情况下,我们并不需要新增链接器配置,只是根据需要对已有链接器进行优化。
属性说明
1) port:端口号,Connector用于创建服务端Socket并进行监听,以等待客户端请求链接。如果该属性设置为0,Tomcat将会随机选择一个可用的端口号给当前Connector使用。
2)protocol :当前Connector支持的访问协议。默认为HTTP/1.1 ,并采用自动切换机制选择一个基于JAVA NIO的链接器或者基于本地APR的链接器(根据本地是否含有Tomcat的本地库判定)。
如果不希望采用上述自动切换的机制,而是明确指定协议,可以使用以下值。
Http协议:
AJP协议
3) connectionTimeOut: Connector接收链接后的等待超时时间,单位为毫秒。-1表示不超时。
4)redirectPort:当前Connector不支持SSL(HTTP协议证书)请求,接收到了一个请求,并且也符合security-constraint约束,需要SSL传输,Catalina自动将请求重定向到指定的端口。
5)executor:指定共享线程池的名称, 也可以通过maxThreads, minSpareThreads等属性配置内部线程池。
6)URIEncoding:用于指定编码URI的字符编码,
Tomcat8.x版本默认的编码为UTF-8,Tomcat7.X版本默认为ISO-8859-1(解决请求字符串乱码问题,Tomcat8版本默认UTF-8不需要指定URI字符编码)。
完整的配置如下:
Engine作为Servlet引擎的顶级元素,内部可嵌入:Cluster、Listener、Realm、Valve和Host。
属性说明:
1)name:用于指定Engine的名称,默认为Catalina。该名称会影响一部分Tomcat的存储路径(如临时文件);
2)defaultHost:默认使用虚拟主机名称,当客户端请求指向的的主机无效时将交由默认虚拟主机处理,默认为localhost。
Host元素用于配置一个虚拟主机,它支持以下嵌入元素:Alias,cluster,Listener,valve,Realm,context,如果在Engine下配置Realm,那么此配置将在当前Engine下的所有Host中共享。同样,如果在Host中配置Realm , 则在当前Host下的所有context中共享。Context中的Realm优先级>Host的Realm优先级>Engine中的Realm优先级。
属性说明:
1)name:当前Host通用的网络名称,必须与DNS服务器上的注册信息一致。Engine中包含的Host必须存在一个名称与Engine的defaultHost设置一致。
2)appBase:当前Host的应用基础目录,当前Host上部署的web应用均在该目录下(可以是绝对目录,相对路径)。默认为webapps。
3)unpackWARs:设置为true, Host在启动时会将appBase目录下war包解压为目录。设置为false,Host将直接从war文件启动。
4)autoDeploy:控制tomcat是否在运行时定期检测并自动部署新增或变更的web应用。
通过给Host添加别名,我们可以实现同一个Host拥有多个网络名称,配置如下:
Context用于配置一个web应用,默认配置如下:
属性描述 :
1)docBase:Web应用目录或War包的部署路径。可以是绝对路径,也可以是相对于Host appBase的相对路径。
2)Path:Web应用的Context路径。如果我们Host名为localhost,则该web应用访问的路径为: http://localhost:8080/myApp
它支持的内嵌元素为:CookieProcessor,Loader,Manager,Realm,Resources,WatchedResource,Jarscanner,Valve.
该配置文件中,主要配置的是Tomcat的用户,角色等信息,用来控制Tomcat中manager,host-manager的访问权限。
web.xml是web应用的描述文件, 它支持的元素及属性来自于servlet规范定义。在Tomcat中,web应用的描述信息包括tomcat/conf/web.xml中默认配置以及web应用WEB-INE/web.xml下的定制配置。
我们可以通过
添加ServletContext初始化参数,它配置了一个键值对,这样我们可以在应用程序中使用javax.servlet.ServletContext.getInitParameter()方法获取参数。 可以直接在servlet中进行应用 。
5.2 会话配置
用于配置web应用会话,包括超时时间Cookie配置以及 会话追踪模式 。它将覆盖server.xml和context.xml
1)session-timeout:超时时间,单位分钟。
2)cookie-config:用于配置会话追踪Cookie
nane:Cookie的名称
domain:Cookie的域名
path: Cookie的路径
comment: 注释
http-only:cookie只能通过HTTP方式进行访问, JS无法读取或修改,此项可以增加网站访问的安全性。
secuze :设置true则此cookie只能通过HTTPS连接传递到服务器,而HTTP连接则不会传递该信息。注意是从浏览器传递到服务器,服务器端的Cookie对像不受此项影响。
max-age:以秒为单位表示cookie的生存期,默认为-1表示是会话Cookie ,浏览器关闭时就会消失。
3)tracking-mode:用于配置会话追踪模式,Servlet3.0版本中支持追踪模式:COOKIE,URL,SSL
ACOOKIE:通过HTTP Cookie 追踪会话是最常用的会话追踪机制, 而且Servlet规范也要求所有的Servlet规范都需要支持Cookie追踪。
B.URL:URL重写是最基本的会话追踪机制。当客户端不支持Cookie时,可以采用URI重写的方式。当采用URI追踪模式时,请求路径需要包含会话标识信息,Servlet容器会根据路径中的会话标识设置请求的会话信息。如:"http: //www.myserver.com/user/index.html;jessionid=1234567890。
C.SSL:对于SSL请求,通过SSL会话标识确定请求会话标识。
Servlet的配置主要是两部分,servlet和servlet-mapping;
配置说明:
1)sexvlet-name:指定servle的名称,该属性在web.xml中唯一。
2)servlet-class:用于指定servlet类名
3)init-param:用于指定servlet的初始化参数, 在应用中可以通过HttpServlet.getInitParameter获取。
4) load-on-startup:用于控制在Web应用启动时,Servlet的加载顺序。值小于0, web应用启动时,不加载该servlet,第一次访问时加载
5)enabled: true ,false。若为false ,表示servlet不处理任何请求。
6)url-pattern:用于指定URL表达式,一个servlet-mapping可以同时配置多个url-pattern。
Servlet 中文件上传配置
配置说明:
1)location:存放生成的文件地址。
2) max-file-size:允许上传的文件最大值。默认值为-1,表示没有限制。
3)max-request-size:针对该multi/form-data请求的最大数量,默认值为-1,表示无限制。
4)file-size-threshold:当数量量大于该值时, 内容会被写入文件。
Listener用于监听servlet中的事件,例如context、request、session对象的创建、修改、删除,并触发响应响应。Listener是 观察者模式 的 实现 ,在servlet中主要用于context、request、session对象的生命周期进行监控。在servlet 2.5规范中共定义了8重Listener。在启动时,ServletContextListener的执行顺序与web.xml中的配置顺序一致,停止时执行顺序相反。
配置说明:
1)filter-name:用于指定过滤器名称,在web.xm1中,过滤器名称必须唯一。
2)filter-class:过滤器的全限定类名,该类必须实现Filter接口。
3)async-supported:该过滤器是否支持异步。
4)init-param:用于配置Filter的初始化参数,可以配置多个,可以通过 FilterConfig.getInitParameter 获取
5)url-pattern:指定该过滤器需要拦截的URL。
Tomcat conf/web.xml中配置了web默认访问页面。
Tomcat启动后会尝从上到下的请求顺序。
如果在项目的WEB-INF目录下的web.xml中配置访问页面,则会覆盖Tomcat中的默认配置。
error-page用于配置web项目访问异常时定向的页面,支持HTTP响应码和异常类两种形式。优化用户体验,保证系统安全。
Tomcat中自定义错误页面放入ROOT目录下。
项目中将错误页面放在web目录下,并且会覆盖Tomcat中的配置。
从早期的Tomcat版本开始,就提供了web版的管理控制台,他们是两个独立的web应用,位于webapps目录下。Tomcat提供的管理应用有用于管理的Host的host-manager和用于管理web应用的manager。
这两个web应用主要作用就是为Tomcat提供了管理后台,可以通过这两个应用去管理Tomcat中所配置的虚拟主机、Tomcat中部署的web应用、Tomcat占用的JVM内存分配、JVM参数配比等
Host-manager主要用来管理 虚拟主机 信息。Tomcat启动之后,可以通过 http://localhost:8080/host-manager/html 访问该web应用。host-manager默认添加了访问权限控制,当打开网址时,需要输入用户名和密码(conf/tomcat-users.xml中配置) 。所以要想访问该页面,需要在conf/tomcat-users.xml中配置,并分配对应的角色:
1)admin-gui:用于控制页面访问权限
2)admin-script:用于控制以简单文本的形式进行访问
配置如下:
界面:
Manager用来管理部署在当前Tomcat上的web应用,访问路径为 http://localhost:8080/manager ,同样manager也添加了页面访问控制,因此我们需要为登录用户分配角色为:
Server Status查看服务器状态,给JVM内存优化参考数据
如何实现网间进程通信?
网间进程通信首先必须解决以下问题。
(1)网间进程的标识问题。在同一主机中,不同的进程可以用进程号(Process ID)唯一标识。
但在网络环境下,各主机独立分配的进程号已经不能唯一地标识一个进程。例如,主机A中某进
程的进程号是5,在B机中也可以存在5号进程,进程号不再唯一了,因此,在网络环境下,仅
仅说“5号进程”就没有意义了。
(2)与网络协议栈连接的问题。网间进程的通信实际是借助网络协议栈实现的。应用进程
把数据交给下层的传输层协议实体,调用传输层提供的传输服务,传输层及其下层协议将数
据层层向下递交,最后由物理层将数据变为信号,发送到网上,经过各种网络设备的寻径和
存储转发.才能到达目的端主机,目的端的网络协议栈再将数据层层上传,最终将数据送交
接收端的应用进程,这个过程是非常复杂的。但是对于网络编程来说,必须要有一种非常简
单的方法,来与网络协议栈连接。这个问题是通过定义套接字网络编程接口来解决的。
(3)多重协议的识别问题。现行的网络体系结构有很多,如TCP/IP. IPX/SPX等,操作系统
往往支持众多的网络协议。不同协议的工作方式不同,地址格式也不同,因此网间进程通信还要解
决多重协议的识别问题。
(4)不同的通信服务的问题。随着网络应用的不同,网间进程通信所要求的通信服务就会
有不同的要求。例如,文件传输服务,传输的文件可能很大,要求传输非常可靠,无差错,无
乱序,无丢失;下载了一个程序,如果丢了几个字节,这个程序可能就不能用了。但对于网上
聊天这样的应用,要求就不高。因此,要求网络应用程序能够有选择地使用网络协议栈提供的
网络通信服务功能。在TCP/IP协议簇中,在传输层有TCP和UDP这两个协议,TCP提供可靠
的数据流传输服务,UDP提供不可靠的数据报传输服务。深入了解它们的工作机制,对于网络
编程是非常必要的。
具体请看http://www.zhaojing520.com/thread-214-1-1.html?_dsign=9cd875fb
C#多线程模拟同时并发如何实现
int num=100;
Thread[] th=new Thread[num];
for (int i = 0; i < num; i++)
{
NewThread n = new NewThread(DoWork);
th[i]=n;
}
for (int i = 0; i < num; i++)
{
th[i].Start();
}
不可能真的全部都同时进行的。系统里也是在多个线程高速切换来分配CPU的占用时间
可参考以下这段代码!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.IO;
namespace Server
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
private void btnStart_Click(object sender, EventArgs e)
{
IPAddress ip = IPAddress.Parse(txtServer.Text);
//网络断点 ip地址和端口号
IPEndPoint point = new IPEndPoint(ip, int.Parse(txtPort.Text));
//创建负责监听用的socket
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
//绑定网络断点
socket.Bind(point);
//监听 10 连接队列的长度
socket.Listen(10);
SetTxt("开始监听");
Thread th = new Thread(Listen);//开启监听的线程
th.IsBackground = true;
th.Start(socket);
}
catch (Exception ex)
{
SetTxt(ex.Message);
}
}
Dictionary
dic = new Dictionary
();
void Listen(object o)
{
//负责监听用的socket
Socket socket = o as Socket;
while (true)
{
try
{
//创建负责通信用的socket
Socket connSocket = socket.Accept();
//获取客户端ip和端口
string ipStr = connSocket.RemoteEndPoint.ToString();
SetTxt(ipStr + ":连接成功");
//填充下拉框
cboUsers.Items.Add(ipStr);
//
dic.Add(ipStr, connSocket);
//开启线程接收消息
Thread th = new Thread(RecMsg);
th.IsBackground = true;
th.Start(connSocket);
}
catch (Exception ex)
{
SetTxt(ex.Message);
}
}
}
void RecMsg(object o)
{
Socket connSocket = o as Socket;
byte[] buffer = new byte[1024 * 1024 * 5];
while (true)
{
try
{
//count实际收到的字节个数
int count = connSocket.Receive(buffer);
string ipStr = connSocket.RemoteEndPoint.ToString();
if (count == 0)
{
SetTxt(ipStr + ":断开连接");
connSocket.Shutdown(SocketShutdown.Both);
connSocket.Close();
break;
}
string msg = Encoding.UTF8.GetString(buffer, 0, count);
SetTxt(ipStr + ":" + msg);
}
catch (Exception ex)
{
SetTxt(ex.Message);
break;
}
}
}
void SetTxt(string t)
{
txtLog.AppendText(t + "\r\n");
}
//发送文字消息
private void btnSend_Click(object sender, EventArgs e)
{
if (cboUsers.SelectedIndex > -1)
{
string key = cboUsers.Text;
byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);
List
list = new List
();
list.Add(1); //协议 1 文字
list.AddRange(buffer);
dic[key].Send(list.ToArray());
}
else
{
MessageBox.Show("请选择客户端");
}
}
//选择路径
private void btnSelect_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
txtPath.Text = ofd.FileName;
}
}
//发送文件
private void btnSendFile_Click(object sender, EventArgs e)
{
if (cboUsers.SelectedIndex > -1)
{
string key = cboUsers.Text;
//dic[key]
//判断文件是否存在
if (txtPath.Text.Length > 0)
{
using (FileStream fs = new FileStream(txtPath.Text,FileMode.Open))
{
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
List
list = new List
();
list.Add(2 ); //协议 2 文件
list.AddRange(buffer);
dic[key].Send(list.ToArray());
}
}
else
{
MessageBox.Show("请选择文件");
}
}
else
{
MessageBox.Show("请选择客户端");
}
}
//震动
private void btnZD_Click(object sender, EventArgs e)
{
if (cboUsers.SelectedIndex > -1)
{
string key = cboUsers.Text;
byte[] buffer = new byte[1];
buffer[0] = 3; //协议 3 震动
dic[key].Send(buffer);
}
else
{
MessageBox.Show("请选择客户端");
}
}
}
}
8080端口被占用,怎么才能用8080端口做映射
试试这个方法:
在windows命令行窗口下执行:
C:\>netstat -aon|findstr "8080"
TCP 127.0.0.1:8080 0.0.0.0:0 LISTENING 2448
看到了吗,端口被进程号为2448的进程占用,继续执行下面命令:
C:\>tasklist|findstr "2448"
thread.exe 2016 Console 0 16,064 K
很清楚吧,thread占用了你的端口,Kill it
如果第二步查不到,那就开任务管理器,看哪个进程是2448,然后杀之即可。
在使用tomcat中,经常碰到默认的8080端口被占用,有时想查下究竟是那个程序在占用着这个端口;这是可以到网站找个软件什么的,或则使用防火墙来查看使用的端口;其实没有这个必要,在windows中有个dos命令可以查看当前端口使用情况的, 这个命令就是netstat,这个命令带有很多参数可用,可以通过 -help参数来查看,比如:要查看所有的连接和监听端口,可以加上-a参数,要显示每个连接所属的进程id,可以加上-o参数;查到了进程id后,你可以在windows的进程管理器中找到对应pid的进程,默认情况下windows的进程管理器是不显示pid的,你可以通过在[查看]->[选择列]中选种 查看pid,然后进程查看器中就会显示pid了
netstat的全部参数及说明如下:
显示协议统计信息和当前 TCP/IP 网络连接。
NETSTAT [-a] [-b] [-e] [-n] [-o] [-p proto] [-r] [-s] [-v] [interval]
-a 显示所有连接和监听端口。
-b 显示包含于创建每个连接或监听端口的
可执行组件。在某些情况下已知可执行组件
拥有多个独立组件,并且在这些情况下
包含于创建连接或监听端口的组件序列
被显示。这种情况下,可执行组件名
在底部的 [] 中,顶部是其调用的组件,
等等,直到 TCP/IP 部分。注意此选项
可能需要很长时间,如果没有足够权限
可能失败。
-e 显示以太网统计信息。此选项可以与 -s
选项组合使用。
-n 以数字形式显示地址和端口号。
-o 显示与每个连接相关的所属进程 ID。
-p proto 显示 proto 指定的协议的连接;proto 可以是
下列协议之一: TCP、UDP、TCPv6 或 UDPv6。
如果与 -s 选项一起使用以显示按协议统计信息,proto 可以是下列协议
之一:
IP、IPv6、ICMP、ICMPv6、TCP、TCPv6、UDP 或 UDPv6。
-r 显示路由表。
-s 显示按协议统计信息。默认地,显示 IP、
IPv6、ICMP、ICMPv6、TCP、TCPv6、UDP 和 UDPv6 的统计信息;
-p 选项用于指定默认情况的子集。
-v 与 -b 选项一起使用时将显示包含于
为所有可执行组件创建连接或监听端口的
组件。
interval 重新显示选定统计信息,每次显示之间
暂停时间间隔(以秒计)。按 CTRL+C 停止重新
显示统计信息。如果省略,netstat 显示当前
配置信息(只显示一次)
怎么判断自己适合学java啊?
分情况来看:1 如果只是兴趣,入门了解的话,没有多大关系。
2 如果想未来从事开发工作, 那么你需要搭建的是自身的知识体系。
如果你本身就不喜欢数学,或者逻辑思维,想逃避数学和英语,那就没有必要啦。逃得过初一逃不过十五。
目前互联网信息爆炸,将来知识更新速度加快,每个人都是活到老学到老,逃不过去的。
还有开发工作有一些是偏业务的,也就是掌握基本操作后都是重复劳动,数学知识基本用不上。
但是算法和数据分析等,可以需要一定数学功底。
如果你大学期间掌握的数学比较好, 未来的发展路线不就比别人宽一些吗?
与其犹豫,不如点点滴滴的积累!
附带java入门知识列表:
你可以按照这个循序进行学习。
面向对象编程(基础)
1)面向过程和面向对象区别
2)类和对象的概述
3)类的属性和方法
4)创建对象内存分析
5)构造方法(Construtor)及其重载
6)对象类型的参数传递
7)this关键字详解
8)static关键字详解
9)局部代码块、构造代码块和静态代码块
10)package和import详解
11)JavaDoc生成API文档
面向对象编程(进阶)
1)面向对象的三大特性
2)面向对象之--封装(Encapsulation)
3)访问权限修饰符
4)面向对象之--继承(Inheritance)
5)Object类
6)方法重写Override
7)super关键字详解
8)重写equals()和toString()
9)继承中对象创建的内存分析
10)组合
11)面向对象之--多态(Polymorphism)
12)向上转型
13)向下转型
14)instanceof运算符
15)编译时和运行时详解
16)final修饰符
17)抽象类和抽象方法(abstract)
18)接口的定义和实现
19)JDK8的接口新特性
20)接口应用:内部比较器Comparable
21)内部类详解
22)Java的内存管理与垃圾回收
异常机制
1)异常的概述
2)异常的执行过程分析
3)try-catch-finally捕捉异常
4)throw抛出异常
5)throws声明异常
6)异常继承体系
7)运行时异常和编译异常
8)自定义异常
Java常用类
1)Wrapper包装类
2)自动装箱和自动拆箱
3)包装类的源码分析
4)String类的使用与内存原理
5)String类的源码分析
6)StringBuffer
7)StringBuilder
8)字符串处理类性能分析
9)Date类
10)System类
11)DateFormat类
12)Calendar类
13)Math类
14)BigInteger类和BigDecimal类
15)Random类
16)枚举类型
17)File类
18)常见的面试题讲解与分析
数据结构和算法
1)数据结构的概述
2)线性表
3)顺序表
4)链表
5)栈和队列
6)树
7)二叉树
8)二叉查找树
9)二叉平衡树
10)红黑树
11)图
12)冒泡排序
13)选择排序
14)递归
15)折半查找
集合(容器)
1)集合和数组的联系和区别
2)集合框架体系
3)ArrayList的使用和源码分析
4)集合中使用泛型
5)LinkedList的使用和源码分析
6)HashSet的使用和源码分析
7)哈希表及其原理
8)TreeSet的使用和源码分析
9)比较器Comparable和Comparator
10)HashMap的使用和源码分析
11)TreeMap的使用和源码分析
12)Iterator与ListIterator
13)Collections工具类
14)旧集合类Vector、Hashtable
15)集合总结和选择依据
16)泛型接口
17)泛型类
18)泛型方法
IO流
1)IO流的概念
2)IO流的分类及其原理分析
3)文件流FileInputStream、FileOutputStream
4)缓冲流BufferedInputStream、BufferedOutputStream
5)数据流DataInputStream、DataOutputStream
6)对象流ObjectInputStream、ObjectOutputStream
7)序列化和反序列化
8)转换流InputStreamReader、OutputStreamWriter
9)打印流PrintWriter和PrintStream
10)数组流ByteArrayOutputStream、ByteArrayInputStream
11)使用IO流复制文件夹
多线程
1)进程和线程
2)线程的创建与启动
3)创建线程的三种方式对比
4)线程的生命周期
5)线程控制
6)多线程的安全问题与解决办法
7)线程的同步:同步代码块
8)线程的同步:同步方法
9)线程的同步:Lock锁
10)线程的死锁问题
11)线程通信
12)Condition
13)线程的完整生命周期
14)线程池ThreadPoolExecutor
15)ForkJoin框架
16)ThreadLocal类
网络编程
1)计算机网络基础知识
2)网络通信协议
3)OSI参考模型
4)TCP/IP参考模型
5)数据的封装与拆封原理解析
6)TCP协议
7)UDP协议
8)IP地址和端口号
9)URL和Socket
10)使用TCP编程实现登录功能
11)使用UDP编程实现客服系统
12)使用TCP编程实现上传文件
集合提升训练
1)手写ArrayList
2)手写单链表
3)手写LinkedList
4)手写HashMap
5)手写HashSet
6)最新并发集合类
多线程提升训练
1)生产者消费者模式扩展
2)Lock锁和Condition
3)ReadWriteLock
4)BlockingQueue
5)volatile关键字
6)多线程题目练习
7)JDK新特征
8)面试题讲解
如果你的逻辑思维能力强、心态好、自学能力强,那你就很适合学java。首先对于Java ,所有功能都是通过编写代码来实现的,需要开发的人员具有很强的逻辑性和计算性。因此,如果逻辑思维能力强,学习Java仍然会有很大的优势。千锋教育就有线上免费JavaScript线上公开课。 其次。在通常的工作将花大部分时间来解决错误,因为在编写代码甚至符号写错也会导致程序错误,不能达到预期的效果,所以这也需要开发人员耐心的解决问题。最后,工作中从事任何职位都需要不断充电和学习,java岗位也不例外。随着科学技术的发展,各种新技术将继续出现。开发人员需要及时关注这些新技术,并将其转化为自己的技能。如果想了解Java更多相关知识,建议到千锋教育了解一下。千锋教育目前在18个城市拥有22个校区,年培养优质人才20000余人,与国内20000余家企业建立人才输送合作关系,院校合作超600所。
就目前的行业发展前景来说,现在转行做Java开发依然有较好的就业前景,Java语言在全场景开发语言中依然占据比较重要的一席之地,在未来,也有很大的使用空间,且Java语言拥有较强的扩展性和稳定的性能,在各大互联网平台中,得到广泛的应用。
IT行业是众多求职者梦寐以求的就职领域,因其薪水普遍高于其他行业平均工资水平而成为求职者眼中的“宝座”,IT从业人员更有着“IT精英”的美誉,成为行业人才的代表。
想知道自己适不适合学习Java,通过以下几点来测试以下:
1、要对Java感兴趣
俗话说,兴趣是学习最好的老师,在任何学习和工作中,兴趣都是很关键的。目前Java很热门,受关注度高,很多人纯粹为了好就业,就盲目进行学习。最后可能自己学有所成,但却没有兴趣继续从事这项工作,最后后悔的还是自己,浪费了大量的时间和金钱。所以对于Java这种技术性行业,兴趣是非常重要的。
2、有逻辑思维能力、学习心态好
逻辑思维能力这是作为程序员最基本的要求。逻辑思维能力差的人,完全不适合学编程。
Java开发必然离不开编程,这是一种与计算机进行交流的语言,是一种非人类语言,所以一定要具有非常强的逻辑性和运算性,所以此时更要慎重的考虑。是否能够精心并踏实的研究一行行的代码,是否具备较强的逻辑思维能力和完好的学习心态,是从事Java的基础能力。
3、有较强的学习能力
明晰的学习思路,非常好的学习能力,Java作为计算机语言靠的大多也是理解能力和逻辑推理能力。你学习能力强当然就能学习的很轻松。
自学能力要强。知识是无穷的,编程的知识也不是一成不变的,只有不断的学习,才能跟得上时代的步伐。
4、耐心、毅力、时间
编程的学习比较枯燥,并不是一种视觉、听觉艺术的享受;很多功能不可能一下子就会展示出来,所以你肯定需要有耐心才能坚持的住。
以上的回答希望对你有所帮助
首先是看能不能静下心来, 浮躁的人学什么都学不进去的。
编程知识都是别人创造出来的,有规律的东西,不会比高中数学,物理难多少。
所以你 找一个视频,或者书籍, 测试一周,每天学习5小时,看能不能学进去。
喜欢做软件,具有数学基础,还有一些其他兴趣爱好。否则 学程序很枯燥无味,只有少数时间是 学的新技术,等你写代码成了工作就知道了。Java是 比C 更简单的 入门程序。
学习 Java,说白了,就是学习它的语法、功能、结构等。然后按照它的语法编写代码。新手刚接触可能会遇到很多问题,但没关系,这很正常。多看多问,多实践。
再来下判断自己适不适合学Java,首先,在心里问下自己这三个问题,如下:
1、感觉自己对它有兴趣吗?
如果对它不感兴趣,对于零基础的人来说,可能有些难懂。学着学着就开始有了厌学心理,根本学不进去!
2、愿意进一步接触它吗?
网上有很多的学习视频,题主应该先去接触一下,自学一段时间,看看自己是否愿意往下学习,如果产生高额的兴趣,自制力和学习力足够的话,先把基础学扎实,再去考虑是否报班进行系统化的培训。
3、能坚持的学习吗?
如果前两个问题都可以接受,那就是问下自己能否坚持的学下去,如果坚持不下去,那前面的都是白费。哪怕去培训完,但是一两年以后呢?人就是要持之以恒的学习进步,不然很快就会被社会给淘汰,更何况是在更新速度超快的数据时代。
如果以上三个问题都没有问题,个人认为是适合学习Java的。毕竟学一门技术本身就没有适不适合。
以上就是我对这个问题的看法,下面推荐下适合零基础学习的视频资料,可以看看自己是否有兴趣!
视频学习资料:https://www.bilibili.com/video/BV137411V7Y1/?p=186
最后,扣字不易,还望看完点个赞!!!