Thread
thread协议

thread协议Thread协议是一种物联网技术,旨在为低功耗设备提供可互通的通信标准。
它在家庭和建筑物的自动化系统中发挥着重要的作用,并为用户提供方便、高效且安全的智能生活体验。
本文将介绍Thread协议的背景、工作原理以及它在物联网应用中的优势。
Thread协议的背景:随着物联网的发展,越来越多的设备被连接到互联网上,这包括智能手机、智能家居设备、智能家电等。
然而,这些设备之间的通信并不方便,无法进行互操作。
为了解决这个问题,Thread协议应运而生。
Thread协议的工作原理:Thread协议基于IPv6,使用IEEE 802.15.4无线协议作为物理层,具有自配置、自修复和低功耗的特点。
它采用网格网络拓扑结构,可以自动寻找路径以保持设备之间的连接。
此外,Thread还支持多种应用层协议,如CoAP、UDP和TCP,以满足不同应用的需求。
Thread协议在物联网应用中的优势:1. 低功耗:Thread协议使用低功耗的IEEE 802.15.4技术,使得设备能够长时间工作,延长了电池寿命,减少了更换电池的频率。
2. 安全性:Thread协议采用了安全的全网协同认证机制,确保设备之间的通信是私密的,防止了信息被窃取或篡改。
3. 可扩展性:Thread协议支持多个设备加入到网络中,可以根据需要灵活扩展,满足不同规模的应用场景。
4. 互操作性:Thread协议支持与其他通信协议的互操作,如Wi-Fi、Zigbee等,使得不同设备之间能够进行无缝的通信与控制。
5. 稳定性:通过网格网络结构,如果一个设备出现故障,数据可以通过其他路径传输,确保网络的稳定性和可靠性。
使用Thread协议的典型场景包括:1. 智能家居:通过Thread协议连接家中的不同设备,如智能灯泡、温度传感器、摄像头等,实现远程控制和监控功能。
2. 建筑自动化:Thread协议可以用于建筑物的自动化系统,如照明控制、空调控制、安全监控等。
thread的构造方法

thread的构造方法Thread类是Java中用于创建和管理多线程的类,它提供了一些方法来控制线程的生命周期和执行过程。
Thread类有多个构造方法可以使用,我们将详细介绍每个构造方法的功能和用法。
1. Thread(:这是Thread类的默认构造方法,创建一个新的线程对象。
使用这个构造方法创建的线程没有指定线程名和要执行的任务。
2. Thread(Runnable target):这个构造方法是最常用的构造方法之一、它接受一个Runnable接口实现类作为参数,用于指定要执行的任务。
可以通过重写Runnable接口的run(方法来定义线程的具体逻辑。
3. Thread(Runnable target, String name):这个构造方法与上一个构造方法类似,不同之处在于可以指定线程的名称。
线程名称可以帮助我们更好地识别不同的线程,方便线程的管理和调试。
4. Thread(String name):这个构造方法只指定了线程的名称,没有指定要执行的任务。
可以通过继承Thread类并重写其run(方法来定义线程的逻辑。
5. Thread(ThreadGroup group, Runnable target):这个构造方法指定了线程所属的线程组,以及要执行的任务。
线程组用于将多个线程组织起来,可以方便地对它们进行管理和控制。
6. Thread(ThreadGroup group, Runnable target, String name):这个构造方法与上一个构造方法类似,不同之处在于可以指定线程的名称。
7. Thread(ThreadGroup group, Runnable target, String name, long stackSize):这个构造方法与前面的构造方法类似,不同之处在于可以指定线程的堆栈大小。
堆栈大小表示线程执行时所分配的内存空间。
除了以上列出的常用构造方法,Thread类还提供了一些其他的构造方法,用于更精细地控制线程的创建和执行。
thread在java中的用法

thread在java中的用法以下是 20 个关于 Java 中 thread 用法的双语例句:1. 创建一个线程就像点燃一颗火种,new Thread(() ->System.out.println("我是新线程!")).start(); Creating a thread is like lighting a fire, new Thread(() -> System.out.println("I'm a new thread!")).start();2. 线程可以并发执行,这多像一场精彩的赛跑啊!A thread can execute concurrently, just like an exciting race!3. 启动线程就如同放飞一只鸟儿,Thread thread = new Thread(() -> {}); thread.start(); Starting a thread is like releasing a bird, Thread thread = new Thread(() -> {}); thread.start();4. 在线程中执行任务,就像是让小火车在轨道上奔跑起来。
Executinga task in a thread is like making a little train run on the track.5. 我们可以用线程实现多任务处理,这不就像有好多只手同时做事嘛!We can use threads to achieve multitasking, isn't it like having many hands doing things at the same time!6. 线程的同步就像是让舞者们按照统一的节奏跳舞。
The synchronization of threads is like making dancers dance according toa unified rhythm.7. 管理线程就好像指挥一场交响乐演出。
thread 常用方法

thread 常用方法在Java中,`Thread`类和`Runnable`接口是用于实现多线程的常用方式。
以下是`Thread`类和`Runnable`接口中的一些常用方法:1. `start()`: 启动线程。
该方法会调用线程的`run()`方法。
2. `run()`: 线程要执行的代码放在这个方法中。
一旦线程启动,`run()`方法就会被自动执行。
3. `stop()`: 试图停止正在运行的线程。
然而,这个方法已经被废弃,因为它是非安全的,可能会导致死锁。
推荐使用`interrupt()`方法来中断线程。
4. `interrupt()`: 用于中断线程。
它会设置线程的中断状态,并抛出一个`InterruptedException`。
5. `isInterrupted()`: 返回线程的中断状态。
如果线程被中断,则返回true。
6. `sleep(long millis)`: 使当前线程休眠指定的毫秒数。
7. `join()`: 阻止当前线程,直到调用`join()`方法的线程结束执行。
8. `yield()`: 暂停当前线程的执行,使得其他线程可以执行。
9. `currentThread()`: 返回当前正在执行的线程。
10. `holdsLock(Object obj)`: 检查当前线程是否持有一个指定对象的锁。
11. `enumerate(Thread[] array)`: 将指定数组中的所有非守护线程复制到新数组中并返回。
12. `activeCount()`: 返回当前活动的线程数。
注意:为了确保线程安全,应避免在`run()`方法中进行任何同步操作,因为`run()`方法是在调用线程中同步执行的,而不是在独立的线程中执行的。
Thread类(线程)

Thread类(线程)操作系统通过线程对程序的执⾏进⾏管理,当操作系统运⾏⼀个程序的时候,⾸先,操作系统将为这个准备运⾏的程序分配⼀个进程,以管理这个程序所需要的各种资源。
在这些资源之中,会包含⼀个称为主线程的线程数据结构,⽤来管理这个程序的执⾏状态。
在Windows操作系统下,线程的的数据结构包含以下内容: 1、线程的核⼼对象:主要包含线程当前的寄存器状态,当操作系统调度这个线程开始运⾏的时候,寄存器的状态将被加载到CPU中,重新构建线程的执⾏环境,当线程被调度出来的时候,最后的寄存器状态被重新保存到这⾥,已备下⼀次执⾏的时候使⽤。
2、线程环境块(Thread Environment Block,TED):是⼀块⽤户模式下的内存,包含线程的异常处理链的头部。
另外,线程的局部存储数据(Thread Local Storage Data)也存在这⾥。
3、⽤户模式的堆栈:⽤户程序的局部变量和参数传递所使⽤的堆栈,默认情况下,Windows将会被分配1M的空间⽤于⽤户模式堆栈。
4、内核模式堆栈:⽤于访问操作系统时使⽤的堆栈。
在抢先式多任务的环境下,在⼀个特定的时间,CPU将⼀个线程调度进CPU中执⾏,这个线程最多将会运⾏⼀个时间⽚的时间长度,当时间⽚到期之后,操作系统将这个线程调度出CPU,将另外⼀个线程调度进CPU,我们通常称这种操作为上下⽂切换。
在每⼀次的上下⽂切换时,Windows将执⾏下⾯的步骤:将当前的CPU寄存器的值保存到当前运⾏的线程数据结构中,即其中的线程核⼼对象中。
选中下⼀个准备运⾏的线程,如果这个线程处于不同的进程中,那么,还必须⾸先切换虚拟地址空间。
加载准备运⾏线程的CPU寄存器状态到CPU中。
公共语⾔运⾏时CLR(Common Language Runtime)是.Net程序运⾏的环境,它负责资源管理,并保证应⽤和底层操作系统之间必要的分离。
在.Net环境下,CLR中的线程需要通过操作系统的线程完成实际的⼯作,⽬前情况下,.Net直接将CLR中的线程映射到操作系统的线程进⾏处理和调度,所以,我们每创建⼀个线程将会消耗1M以上的内存空间。
Thread详解

Thread详解具体可参考:,这⾥对线程状态的转换及主要函数做⼀下补充。
⼀. 线程状态转换图 注意:1. 调⽤obj.wait()的线程需要先获取obj的monitor,wait()会释放obj的monitor并进⼊等待态。
所以wait()/notify()都要与synchronized联⽤。
详见:1.1 阻塞与等待的区别阻塞:当⼀个线程试图获取对象锁(⾮java.util.concurrent库中的锁,即synchronized),⽽该锁被其他线程持有,则该线程进⼊阻塞状态。
它的特点是使⽤简单,由JVM调度器来决定唤醒⾃⼰,⽽不需要由另⼀个线程来显式唤醒⾃⼰,不响应中断。
等待:当⼀个线程等待另⼀个线程通知调度器⼀个条件时,该线程进⼊等待状态。
它的特点是需要等待另⼀个线程显式地唤醒⾃⼰,实现灵活,语义更丰富,可响应中断。
例如调⽤:Object.wait()、Thread.join()以及等待Lock或Condition。
需要强调的是虽然synchronized和JUC⾥的Lock都实现锁的功能,但线程进⼊的状态是不⼀样的。
synchronized会让线程进⼊阻塞态,⽽JUC⾥的Lock是⽤LockSupport.park()/unpark()来实现阻塞/唤醒的,会让线程进⼊等待态。
但话⼜说回来,虽然等锁时进⼊的状态不⼀样,但被唤醒后⼜都进⼊runnable态,从⾏为效果来看⼜是⼀样的。
⼆. 主要操作2.1 start()新启⼀个线程执⾏其run()⽅法,⼀个线程只能start⼀次。
主要是通过调⽤native start0()来实现。
1public synchronized void start() {2 //判断是否⾸次启动3if (threadStatus != 0)4throw new IllegalThreadStateException();56 group.add(this);78boolean started = false;9try {10 //启动线程11 start0();12 started = true;13 } finally {14try {15if (!started) {16 group.threadStartFailed(this);17 }18 } catch (Throwable ignore) {19/* do nothing. If start0 threw a Throwable then20 it will be passed up the call stack */21 }22 }23 }2425private native void start0();2.2 run()run()⽅法是不需要⽤户来调⽤的,当通过start⽅法启动⼀个线程之后,当该线程获得了CPU执⾏时间,便进⼊run⽅法体去执⾏具体的任务。
thread的用法总结大全
thread的用法总结大全Thread是一个多线程编程的概念,在许多编程语言中都有Thread类或相关的API提供多线程编程的功能。
它允许程序同时执行多个任务,使得程序能够更加高效地利用计算机的资源,同时提高程序的响应速度和并发性。
以下是Thread的用法总结大全:1. 创建线程:- 继承Thread类,重写run()方法,并调用start()方法启动线程。
- 实现Runnable接口,重写run()方法,并通过Thread类的构造函数传入实现了Runnable接口的类。
2. 控制线程:- 使用start()方法启动线程。
- 使用join()方法等待线程执行完毕。
- 使用sleep()方法暂停线程的执行一段时间。
- 使用yield()方法让出当前线程的执行权。
3. 线程同步:- 使用synchronized关键字实现线程的互斥访问。
- 使用wait()、notify()和notifyAll()方法实现线程的等待和唤醒。
- 使用Lock和Condition接口实现线程的同步。
4. 线程间通信:- 使用共享对象作为通信的媒介,如通过共享变量进行数据的传递。
- 使用等待-通知机制实现线程间的通信,即wait()和notify()方法的配合使用。
5. 线程安全:- 使用线程安全的数据结构,如ConcurrentHashMap和CopyOnWriteArrayList。
- 使用线程安全的类,如AtomicInteger和CountDownLatch。
- 使用synchronized关键字或Lock接口实现线程安全。
6. 线程池:- 使用线程池管理线程的创建和销毁,提高线程的利用率和执行效率。
- 使用Executors类创建线程池,如newFixedThreadPool()、newCachedThreadPool()等。
- 使用ThreadPoolExecutor类自定义线程池的参数,如核心线程数、最大线程数和任务队列等。
thread构造方法参数
thread构造方法参数在使用多线程编程时,我们需要使用thread类来创建线程对象。
在创建线程对象时,我们需要使用thread构造方法。
thread构造方法的参数包括线程函数指针、线程函数的参数以及其他线程属性。
线程函数指针指向线程函数,线程函数的参数是传递给线程函数指针的参数。
其他线程属性包括线程的优先级、线程的堆栈大小等。
通常情况下,我们可以使用默认的线程属性,只需要指定线程函数指针和线程函数的参数即可。
例如,下面的代码创建了一个新的线程对象,并将其绑定到一个线程函数:```#include <iostream>#include <thread>using namespace std;void myThreadFunc(int myParam) {cout << 'Hello from thread ' << myParam << endl;}int main() {thread myThread(myThreadFunc, 42);myThread.join();return 0;}```在上面的代码中,thread构造方法的参数包括线程函数指针myThreadFunc和参数42。
线程函数myThreadFunc的参数myParam被设置为42。
除了默认的线程属性,我们还可以使用其他线程属性,如下所示: ```#include <iostream>#include <thread>using namespace std;void myThreadFunc(int myParam) {cout << 'Hello from thread ' << myParam << endl;}int main() {thread myThread(myThreadFunc, 42);myThread.join();thread myThread2(myThreadFunc, 99);myThread2.detach();return 0;}```在上面的代码中,我们创建了两个线程对象。
thread 协议
thread 协议Thread 协议。
在计算机科学中,线程(thread)是操作系统能够进行运算调度的最小单位。
它被包含在进程之中,是进程中的实际运作单位。
一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
线程协议(Thread Protocol)是指在多线程编程中,线程之间如何进行协作和通信的一种规范。
线程协议的设计对于保证多线程程序的正确性、性能和可维护性具有重要意义。
下面将介绍一些常见的线程协议及其应用。
1. 互斥锁(Mutex)。
互斥锁是线程协议中常见的一种同步原语。
当线程需要访问共享资源时,它需要先获取互斥锁,如果该资源已经被其他线程占用,那么当前线程就会被阻塞,直到该资源被释放。
互斥锁能够有效地避免多个线程同时访问共享资源导致的数据竞争问题,确保了程序的正确性。
2. 条件变量(Condition Variable)。
条件变量是一种线程协议,它允许线程在特定的条件下等待或者被唤醒。
在多线程编程中,条件变量通常与互斥锁结合使用,当某个条件不满足时,线程会释放互斥锁并等待条件变量的信号,当条件满足时,其他线程会通过条件变量发送信号唤醒等待的线程。
条件变量的使用可以有效地减少线程的忙等待,提高程序的效率。
3. 信号量(Semaphore)。
信号量是一种更为通用的线程协议,它可以用来控制多个线程对共享资源的访问。
信号量维护着一个计数器,当线程需要访问共享资源时,它需要先获取信号量,如果计数器大于0,线程可以继续执行并将计数器减一;如果计数器等于0,线程就会被阻塞,直到其他线程释放资源。
信号量的使用可以灵活地控制资源的访问数量,从而实现对共享资源的合理调度。
4. 屏障(Barrier)。
屏障是一种线程协议,它允许多个线程在某个点上进行同步。
当线程到达屏障点时,它会被阻塞,直到所有其他线程也到达屏障点,然后所有线程一起被释放。
屏障的使用可以确保多个线程在某个关键点上同时执行,从而实现对程序执行流程的控制。
thread 写法
thread 写法一、基本概念Thread 是编程中的一个重要概念,指的是程序中的执行线程。
在多线程编程中,多个任务可以同时执行,从而提高程序的运行效率。
在 Java、C#、Python 等编程语言中,都有对线程的支持。
二、Thread 的创建创建 Thread 的方式因编程语言而异。
以 Java 和 C# 为例,介绍两种常见的创建方式。
1. Java 中创建 Thread 的方式:* 继承 Thread 类:需要重写 run() 方法,在该方法中编写线程要执行的代码。
* 实现 Runnable 接口:将实现该接口的对象作为参数传递给 Thread 对象,然后调用 Thread 对象的 start() 方法启动线程。
2. C# 中创建 Thread 的方式:* 使用 Thread 类:需要创建 Thread 对象,并调用其 Start() 方法启动线程。
在 Start() 方法内部,需要调用委托(Delegate)来指定线程要执行的代码。
无论是哪种方式,都需要在创建线程后调用 start() 方法启动线程,并在需要的时候调用 Thread 对象或委托的 Join() 方法等待线程执行完毕。
三、线程的同步和互斥在多线程编程中,为了保证数据的一致性和正确性,通常需要进行线程同步和互斥。
常见的同步机制包括锁(Lock)和信号量(Semaphore)等。
在使用这些机制时,需要注意避免死锁和竞态条件等问题。
四、线程的优先级和调度大多数编程语言都支持线程的优先级和调度。
通过设置线程的优先级,可以控制线程的执行顺序。
不同的编程语言有不同的调度机制,需要根据具体语言文档进行了解和设置。
五、常见问题及解决方案在多线程编程中,常见的问题包括竞态条件、死锁、线程泄露等。
针对这些问题,需要采取相应的解决方案,如使用锁的粒度控制、合理分配资源、避免长时间占用资源等。
六、线程的应用场景线程在多任务环境下具有很高的应用价值,可以大大提高程序的运行效率。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一.线程:线程是一个并发执行的顺序流,一个进程包括多个顺序执行流程,这执行流程称为线程.线程是一个操作系统创建并维
护的一个资源,对操作系统来说JVM就是一个进程.对于单
CPU系统来说,某一个时刻只可能由一个线程在运行。
一个Thread对象就表示一个线程。
线程由三部分组成:
(1).CPU分配给线程的时间片
(2).线程代码(写在run方法中)
(3).线程数据
进程是独立的数据空间,线程是共享的数据空间.
线程对象存在于虚拟机堆空间的一块连续的地址空间(静态)
注意:1.线程是动态的,与线程对象是两回事.
2.线程对象与其他对象不同的是线程对象能够到底层去申
请管理一个线程资源。
3.只有对线程对象调用start()方法才是到底层去申请管理
一个线程资源。
4.任务并发执行是一个宏观概念,微观上是串行的。
二.进程的调度
进程的调度是由OS负责的(有的系统为独占式,有的系统为共享式,根据重要性,进程有优先级)。
由OS将时间分为若干个时间
三.线程有两种实现方式:
第一种方式:
class MyThread extends Thread{
public void run(){
需要进行执行的代码,如循环。
}
}
public class TestThread{
main(){
Thread t1=new Mythread();
T1.start();
}
}
只有等到所有的线程全部结束之后,进程才退出。
第二种方式:通过接口实现继承
Class MyThread implements Runnable{
Public void run(){
Runnable target=new MyThread();
Thread t3=new Thread(target);
Thread.start();//启动线程
}
}
四.下面为线程中的7中非常重要的状态:
(有的书上也只有认为前五种状态:而将“锁池”和“等待队列”都看成是“阻塞”状态的特殊情况:这种认识也是正确的,但是将“锁池”和“等待队列”单独分离出来有利于对程序的理解)
注意:图中标记依次为
①输入完毕;②wake up③t1退出
⑴如等待输入(输入设备进行处理,而CUP不处理),则放入阻塞,直到输入完毕。
⑵线程休眠sleep()
⑶t1.join()指停止main(),然后在某段时间内将t1加入运行队列,直到t1退出,main()才结束。
特别注意:①②③与⑴⑵⑶是一一对应的。
进程的休眠:Thread sleep(1000);//括号中以毫秒为单位
当main()运行完毕,即使在结束时时间片还没有用完,CPU也放弃此时间片,继续运行其他程序。
Try{Thread.sleep(1000);}
Catch(Exception e){e.printStackTrace(e);}
T1.join()表示运行线程放弃执行权,进入阻塞状态。
当t1结束时,main()可以重新进入运行状态。
T1.join实际上是把并发的线程编程并行运行。
五.线程的优先级:
议使用,因为不同操作系统的优先级并不相同,使得程序不具备跨平台性,这种优先级只是粗略地划分)。
设置线程优先级:setPriority(Thread.MAX_PRIORITY);
注:程序的跨平台性:除了能够运行,还必须保证运行的结果。
当一个线程对象调用yield()方法时会马上交出执行权,回到可运行状态,等待OS的再次调用。
由一个高优先级的线程进入运行状态。
注:设置线程优先级只有在独占式系统中有效。
程序员需要关注的线程同步和互斥的问题。
多线程的并发一般不是程序员决定,而是由容器决定。
六、多线程出现故障的原因:
(1).两个线程同时访问一个数据资源(该资源称为临界资源),形成
数据发生不一致和不完整。
(2).数据的不一致往往是因为一个线程中的两个关联的操作只完成
了一步。
避免以上的问题可采用对数据进行加锁的方法
七、对象锁Synchronized
1.互斥锁标记:每个对象除了属性和方法,都有一个monitor(互斥锁标记),用来将这个对象交给一个线程,只有拿到monitor的线程才能够访问这个对象。
2.Synchronized:这个修饰词可以用来修饰方法和代码块
Obj.setValue(123);
Synchronized用来修饰代码块时,该代码块成为同步代码块。
Synchronized用来修饰方法,表示当某个线程调用这个方法之后,其他的事件不能再调用这个方法。
只有拿到obj标记的线程才能够执行代码块。
注意:(1)Synchronized一定使用在一个方法中。
(2)锁标记是对象的概念,加锁是对对象加锁,目的是
在线程之间进行协调。
(3)当用Synchronized修饰某个方法的时候,表示该
方法都对当前对象加锁。
(4)给方法加Synchronized和用Synchronized修饰
对象的效果是一致的。
(5)一个线程可以拿到多个锁标记,一个对象最多只
能将monitor给一个线程。
(6)构造方法和抽象方法不能加synchronized;
(7)一般方法和静态方法可以加synchronized同步。
(8)Synchronized是以牺牲程序运行的效率为代价
的,因此应该尽量控制互斥代码块的范围。
(9)方法的Synchronized特性本身不会被继承,只能
覆盖。
八、锁池
本状态中的阻塞,称为锁池。
2.每个对象都有自己的一个锁池的空间,用于放置等待运行的线程。
这些线程中哪个线程拿到锁标记由系统决定。
3.死锁:锁标记如果过多,就会出现线程等待其他线程释放锁标记,而又都不释放自己的锁标记供其他线程运行的状
况。
就是死锁。
死锁的问题通过线程间的通信的方式进行解决。
九、线程间通信:
1.线程间通信机制实际上也就是协调机制。
线程间通信使用的空间称之为对象的等待队列,这个队列也是属于对象的空间的。
注:那么学到这里,我们已经知道一个对象除了由属性和方法之外还有互斥锁标记、锁池空间和等待队列空间。
2.Object类中又一个wait(),在运行状态中,线程调用wait(),此时表示着线程将释放自己所有的锁标记,同时进入这个对象的等待队列。
等待队列的状态也是阻塞状态,只不过线程释放自己的锁标记。
3.Notify()
如果一个线程调用对象的notify(),就是通知对象等待队列的一个线程出列。
进入锁池。
如果使用notifyall()则通知等待队列
注意:只能对加锁的资源进行wait()和notify()。
我们应该用notifyAll取代notify,因为我们用notify释放出的一个线程是不确定的,由OS决定。
释放锁标记只有在Synchronized代码结束或者调用wait()。
注意锁标记是自己不会自动释放,必须有通知。
注意在程序中判定一个条件是否成立时要注意使用WHILE要比使用IF要严密。
WHILE会放置程序饶过判断条件而造成越界。
多线程中的重点:实现多线程的两种方式,Synchronized,以及生产者和消费者问题
(ProducerConsumer.java文件)。
补充说明:通过Synchronized,可知Vector较ArrayList方法的区别就是Vector所有的方法都有Synchronized。
所以Vector更为安全。
同样:Hashtable较HashMap也是如此。