通知设置 新通知
Java多线程相关知识【10】--解释volatile关键字
micform-admin 发表了文章 • 0 个评论 • 927 次浏览 • 2019-10-18 15:55
# Java多线程相关知识【10】--解释volatile关键字
菜鸟的一个学习笔记,大神请绕路。
## 1.问题的引入
假设两个人同时对银行的一个账户进行存入1元钱操作,若银行未进行一定的保障,则有可能造成两个人同时存入一元钱,而这个账户仅仅会添加一元钱,而将会丢失一元钱的情况,那么如何保证这种情况不被发生呢?
## 2.问题发生的原因
由于两人同时存入前,计算机读取数据时,并不会判断在读取数据后是否会发成改变,并且都将相应读到的数据存到计算机内,而仅对当前读到的数据进行保存,而忽略了多个人同时操作时发生的与时间有关的问题,故会造成读到脏数据的情况。(详见操作系统,多线程相关原理的解释)
## 3.解决的方法
### 3.1.解决方法的理论
### 3.1.1总线加锁
总线加锁即当操作共享数据时,将会为访问的数据进行全部加锁的方式,这种方式虽然能解决相关程序的运行问题,但是,同样也会造成系统的运行效率低下等问题。
### 3.1.2.使用cpu高速缓存一致性协议(Intel 提出)
思想:cpu写入数据时,发现被共享时,会通知其他拥有副本的cpu需要立即更新缓存,即之前的信息失效,其他的cpu在收到信号后,会重新到相应内存区重新获取相应数据,这也就解决多个线程访问时数据不一致的问题。而Java在使用volatile关键字时,即使用了这个设计的思想。
### 3.2.Java中的多线程的三大原则
#### 3.2.1.原子性(atomic)
一个操作要么都成功,要么都失败,不能因为任何原因被中断。
#### 3.2.2.有序性(order)
相应的操作需要按顺序执行(重排序为只要求结果一致性(重排序能优化单线程的执行效率),但在多线程中,会产生相关的错误)
##### Java默认提供的有序性(happens-before)
1. 代码执行时顺序为写在前面的代码先发生,写在后面的后发生。
2. 解锁操作必须在锁之后。
3. 多线程时,volatile修饰的关键字先执行写操作,后执行读操作。
4. 如果A操作先于B操作,B操作先于C操作,那么A操作必定先于C操作。
5. 在线程启动时,线程的创建必定优先于线程的执行。
6. 在线程中断时,线程的中断操作(interrupt)必须发生在捕获异常发生之前。
7. 对象的初始化,必须发生在销毁之前。
8. 线程的所有操作必须发生在线程的销毁之前。
#### 3.3.3.可见性(visable)
任何时间看到的数据应为最新的数据,而并非为旧的数据(防止操作系统的与时间有关的错误)
### 3.3.Java中的解决方法(使用volatile)
在Java中,未了解决操作系统中的与时间有关的错误的问题时,为了简单起见,通常会使用volatile关键字,但本关键字也有一定的使用限制,具体如下:
#### 3.3.1.使用volatile关键字的优点和缺点
1. 一旦此变量被关键字修饰,则虚拟机则保证了执行的可见性(V)和有序性(O),但并不能保证这个变量的原子性(A)。
2. 保证重排序时,指令的执行顺序不被修改
3. 强制使缓存的数据立刻写入主存
4. 若对关键字修饰的变量进行写操作,则会是其他cpu的缓存的数据在写入修改后立即失效。
#### 3.3.2.volatile关键字的使用场景
1. 需要进行状态量的标记时,可使用本关键字。
2. 需要保证关键字修饰的语句的执行的先后顺序不发送改变,即运行一致性时,可使用本关键字。 查看全部
菜鸟的一个学习笔记,大神请绕路。
## 1.问题的引入
假设两个人同时对银行的一个账户进行存入1元钱操作,若银行未进行一定的保障,则有可能造成两个人同时存入一元钱,而这个账户仅仅会添加一元钱,而将会丢失一元钱的情况,那么如何保证这种情况不被发生呢?
## 2.问题发生的原因
由于两人同时存入前,计算机读取数据时,并不会判断在读取数据后是否会发成改变,并且都将相应读到的数据存到计算机内,而仅对当前读到的数据进行保存,而忽略了多个人同时操作时发生的与时间有关的问题,故会造成读到脏数据的情况。(详见操作系统,多线程相关原理的解释)
## 3.解决的方法
### 3.1.解决方法的理论
### 3.1.1总线加锁
总线加锁即当操作共享数据时,将会为访问的数据进行全部加锁的方式,这种方式虽然能解决相关程序的运行问题,但是,同样也会造成系统的运行效率低下等问题。
### 3.1.2.使用cpu高速缓存一致性协议(Intel 提出)
思想:cpu写入数据时,发现被共享时,会通知其他拥有副本的cpu需要立即更新缓存,即之前的信息失效,其他的cpu在收到信号后,会重新到相应内存区重新获取相应数据,这也就解决多个线程访问时数据不一致的问题。而Java在使用volatile关键字时,即使用了这个设计的思想。
### 3.2.Java中的多线程的三大原则
#### 3.2.1.原子性(atomic)
一个操作要么都成功,要么都失败,不能因为任何原因被中断。
#### 3.2.2.有序性(order)
相应的操作需要按顺序执行(重排序为只要求结果一致性(重排序能优化单线程的执行效率),但在多线程中,会产生相关的错误)
##### Java默认提供的有序性(happens-before)
1. 代码执行时顺序为写在前面的代码先发生,写在后面的后发生。
2. 解锁操作必须在锁之后。
3. 多线程时,volatile修饰的关键字先执行写操作,后执行读操作。
4. 如果A操作先于B操作,B操作先于C操作,那么A操作必定先于C操作。
5. 在线程启动时,线程的创建必定优先于线程的执行。
6. 在线程中断时,线程的中断操作(interrupt)必须发生在捕获异常发生之前。
7. 对象的初始化,必须发生在销毁之前。
8. 线程的所有操作必须发生在线程的销毁之前。
#### 3.3.3.可见性(visable)
任何时间看到的数据应为最新的数据,而并非为旧的数据(防止操作系统的与时间有关的错误)
### 3.3.Java中的解决方法(使用volatile)
在Java中,未了解决操作系统中的与时间有关的错误的问题时,为了简单起见,通常会使用volatile关键字,但本关键字也有一定的使用限制,具体如下:
#### 3.3.1.使用volatile关键字的优点和缺点
1. 一旦此变量被关键字修饰,则虚拟机则保证了执行的可见性(V)和有序性(O),但并不能保证这个变量的原子性(A)。
2. 保证重排序时,指令的执行顺序不被修改
3. 强制使缓存的数据立刻写入主存
4. 若对关键字修饰的变量进行写操作,则会是其他cpu的缓存的数据在写入修改后立即失效。
#### 3.3.2.volatile关键字的使用场景
1. 需要进行状态量的标记时,可使用本关键字。
2. 需要保证关键字修饰的语句的执行的先后顺序不发送改变,即运行一致性时,可使用本关键字。 查看全部
# Java多线程相关知识【10】--解释volatile关键字
菜鸟的一个学习笔记,大神请绕路。
## 1.问题的引入
假设两个人同时对银行的一个账户进行存入1元钱操作,若银行未进行一定的保障,则有可能造成两个人同时存入一元钱,而这个账户仅仅会添加一元钱,而将会丢失一元钱的情况,那么如何保证这种情况不被发生呢?
## 2.问题发生的原因
由于两人同时存入前,计算机读取数据时,并不会判断在读取数据后是否会发成改变,并且都将相应读到的数据存到计算机内,而仅对当前读到的数据进行保存,而忽略了多个人同时操作时发生的与时间有关的问题,故会造成读到脏数据的情况。(详见操作系统,多线程相关原理的解释)
## 3.解决的方法
### 3.1.解决方法的理论
### 3.1.1总线加锁
总线加锁即当操作共享数据时,将会为访问的数据进行全部加锁的方式,这种方式虽然能解决相关程序的运行问题,但是,同样也会造成系统的运行效率低下等问题。
### 3.1.2.使用cpu高速缓存一致性协议(Intel 提出)
思想:cpu写入数据时,发现被共享时,会通知其他拥有副本的cpu需要立即更新缓存,即之前的信息失效,其他的cpu在收到信号后,会重新到相应内存区重新获取相应数据,这也就解决多个线程访问时数据不一致的问题。而Java在使用volatile关键字时,即使用了这个设计的思想。
### 3.2.Java中的多线程的三大原则
#### 3.2.1.原子性(atomic)
一个操作要么都成功,要么都失败,不能因为任何原因被中断。
#### 3.2.2.有序性(order)
相应的操作需要按顺序执行(重排序为只要求结果一致性(重排序能优化单线程的执行效率),但在多线程中,会产生相关的错误)
##### Java默认提供的有序性(happens-before)
1. 代码执行时顺序为写在前面的代码先发生,写在后面的后发生。
2. 解锁操作必须在锁之后。
3. 多线程时,volatile修饰的关键字先执行写操作,后执行读操作。
4. 如果A操作先于B操作,B操作先于C操作,那么A操作必定先于C操作。
5. 在线程启动时,线程的创建必定优先于线程的执行。
6. 在线程中断时,线程的中断操作(interrupt)必须发生在捕获异常发生之前。
7. 对象的初始化,必须发生在销毁之前。
8. 线程的所有操作必须发生在线程的销毁之前。
#### 3.3.3.可见性(visable)
任何时间看到的数据应为最新的数据,而并非为旧的数据(防止操作系统的与时间有关的错误)
### 3.3.Java中的解决方法(使用volatile)
在Java中,未了解决操作系统中的与时间有关的错误的问题时,为了简单起见,通常会使用volatile关键字,但本关键字也有一定的使用限制,具体如下:
#### 3.3.1.使用volatile关键字的优点和缺点
1. 一旦此变量被关键字修饰,则虚拟机则保证了执行的可见性(V)和有序性(O),但并不能保证这个变量的原子性(A)。
2. 保证重排序时,指令的执行顺序不被修改
3. 强制使缓存的数据立刻写入主存
4. 若对关键字修饰的变量进行写操作,则会是其他cpu的缓存的数据在写入修改后立即失效。
#### 3.3.2.volatile关键字的使用场景
1. 需要进行状态量的标记时,可使用本关键字。
2. 需要保证关键字修饰的语句的执行的先后顺序不发送改变,即运行一致性时,可使用本关键字。
Java多线程相关知识【9】--设计模式--WaitSet方式
micform-admin 发表了文章 • 0 个评论 • 1239 次浏览 • 2019-10-18 15:55
[TOC]
# Java多线程相关知识【9】--设计模式--WaitSet方式
## 1.WaitSet的具体含义
由于一个线程的生命周期可能存在运行,阻塞,就绪等状态,而使用WaitSet的Wait后,线程则可直接进入阻塞状态,而等待相应Set的信号唤醒。
当线程被唤醒后,线程并非能直接进入运行状态,相应的,则可能进入就绪状态,等待系统调度进入相应的执行状态。
在多个线程被唤醒时,唤醒的顺序并非先进先出的,即相应的进程并非有一定的执行顺序。
线程被唤醒后,需重新申请锁,且在申请后将会返回唤醒的位置,并非重新运行代码。
## 2.Java中WaitSet的实现方法
在WaitSet中,wait相当于对象中的wait()方法。
具体使用的代码如下:
```java
[对象].wait();
```
在WaitSet中,Set相当于对象中的notify()方法。
具体使用的代码如下:
```java
[对象].notify();
``` 查看全部
# Java多线程相关知识【9】--设计模式--WaitSet方式
## 1.WaitSet的具体含义
由于一个线程的生命周期可能存在运行,阻塞,就绪等状态,而使用WaitSet的Wait后,线程则可直接进入阻塞状态,而等待相应Set的信号唤醒。
当线程被唤醒后,线程并非能直接进入运行状态,相应的,则可能进入就绪状态,等待系统调度进入相应的执行状态。
在多个线程被唤醒时,唤醒的顺序并非先进先出的,即相应的进程并非有一定的执行顺序。
线程被唤醒后,需重新申请锁,且在申请后将会返回唤醒的位置,并非重新运行代码。
## 2.Java中WaitSet的实现方法
在WaitSet中,wait相当于对象中的wait()方法。
具体使用的代码如下:
```java
[对象].wait();
```
在WaitSet中,Set相当于对象中的notify()方法。
具体使用的代码如下:
```java
[对象].notify();
``` 查看全部
[TOC]
# Java多线程相关知识【9】--设计模式--WaitSet方式
## 1.WaitSet的具体含义
由于一个线程的生命周期可能存在运行,阻塞,就绪等状态,而使用WaitSet的Wait后,线程则可直接进入阻塞状态,而等待相应Set的信号唤醒。
当线程被唤醒后,线程并非能直接进入运行状态,相应的,则可能进入就绪状态,等待系统调度进入相应的执行状态。
在多个线程被唤醒时,唤醒的顺序并非先进先出的,即相应的进程并非有一定的执行顺序。
线程被唤醒后,需重新申请锁,且在申请后将会返回唤醒的位置,并非重新运行代码。
## 2.Java中WaitSet的实现方法
在WaitSet中,wait相当于对象中的wait()方法。
具体使用的代码如下:
```java
[对象].wait();
```
在WaitSet中,Set相当于对象中的notify()方法。
具体使用的代码如下:
```java
[对象].notify();
```
Java多线程相关知识【8】--设计模式--Singleton方式
micform-admin 发表了文章 • 0 个评论 • 1234 次浏览 • 2019-10-18 15:54
[TOC]
# Java多线程相关知识【8】--设计模式--Singleton方式
## 一、四种单例模式(Singleton)的优缺点在多线程下
### 1.饿汉式
优点:实现简单。
缺点:使用前即主动加载,若很长时间未使用,易造成内存浪费。
代码实现如下所示:
```java
/**
* 饿汉式单例模式
*/
public class SingelazeHangers {
//创建类时即创建了元素
private static SingelazeHangers instance = new SingelazeHangers();
private SingelazeHangers() {
}
/**
* 真正执行时调用此元素
* @return 返回单例设计
*/
public static SingelazeHangers getInstance() {
return instance;
}
//测试实例加载
public static void main(String[] args) {
SingelazeHangers s=SingelazeHangers.getInstance();
}
}
```
### 2.懒汉式
优点:需要时才会加载,减少内存的浪费。
缺点:多个线程同时获取时,可能会被创建多次,易产生问题,可能不是单个实例。
```java
/**
* 懒汉式单例模式
*/
public class SingelazeLazyers {
//创建时并未创建类
public static SingelazeLazyers instance = null;
private SingelazeLazyers() {
}
/**
* 需要时进行类的创建
* @return 返回创建的结果
*/
public static SingelazeLazyers getInstance() {
if (instance == null)
instance = new SingelazeLazyers();
return instance;
}
//测试单例模式
public static void main(String[] args) {
SingelazeLazyers s=SingelazeLazyers.getInstance();
}
}
```
### 3.懒汉式改进
#### 1.函数加锁
优点:解决懒汉加载可能创建多个实例的问题。
缺点:性能低下。
说明:多线程使用时,虽然会解决创建非单例的问题,但是,在创建后,所有的线程依然需要进行等待,会浪费大量的时间进行单例的获取。
代码实现如下:
```java
/**
* 懒汉式单例模式(加类锁)
*/
public class SingelazeLazyersClassLock {
//创建时并未创建类
public static SingelazeLazyersClassLock instance = null;
private SingelazeLazyersClassLock() {
}
/**
* 需要时进行类的创建(关键字在此添加)
* @return 返回创建的结果
*/
public synchronized static SingelazeLazyersClassLock getInstance() {
if (instance == null)
instance = new SingelazeLazyersClassLock();
return instance;
}
//测试单例模式
public static void main(String[] args) {
SingelazeLazyersClassLock s= SingelazeLazyersClassLock.getInstance();
}
}
```
#### 2.双重判断
优点:解决函数加锁产生的性能问题。
缺点:易产生空指针异常。
说明:多线程使用时,第一个获取的元素释放了相关的锁,但是,对象内部的内容并未创建完成,导致其他线程调用到方法时,虽然拿到了对象,但对象内,需要使用的方法并未被实例化。
代码实现如下:
```java
/**
* 懒汉式单例模式(双重锁)
*/
public class SingelazeLazyersDoubleCheck {
//创建时并未创建类
public static SingelazeLazyersDoubleCheck instance = null;
private SingelazeLazyersDoubleCheck() {
}
/**
* 需要时进行类的创建(内容在此修改)
*
* @return 返回创建的结果
*/
public static SingelazeLazyersDoubleCheck getInstance() {
if (instance == null) {
synchronized (SingelazeLazyersDoubleCheck.class) {
if (instance == null)
instance = new SingelazeLazyersDoubleCheck();
}
}
return instance;
}
//测试单例模式
public static void main(String[] args) {
SingelazeLazyersDoubleCheck s = SingelazeLazyersDoubleCheck.getInstance();
}
}
```
## 二、三种优雅实现单例的方法
### 1.双重判断的改进
volatile关键字非原子性的,他可保证内存是可见的,并能够指定编译器及虚拟机不可对相关的语句进行优化,并保证在读相应内存区时,相关元素的创建必须完成。
缺点:虚拟机未优化,执行效率低下。
```java
/**
* 懒汉式单例模式(双重锁,内存可见式)
*/
public class SingelazeLazyersDoubleCheckVolatile {
//创建时并未创建类(关键字在此添加)
public volatile static SingelazeLazyersDoubleCheckVolatile instance = null;
private SingelazeLazyersDoubleCheckVolatile() {
}
/**
* 需要时进行类的创建
*
* @return 返回创建的结果
*/
public static SingelazeLazyersDoubleCheckVolatile getInstance() {
if (instance == null) {
synchronized (SingelazeLazyersDoubleCheckVolatile.class) {
if (instance == null)
instance = new SingelazeLazyersDoubleCheckVolatile();
}
}
return instance;
}
//测试单例模式
public static void main(String[] args) {
SingelazeLazyersDoubleCheckVolatile s = SingelazeLazyersDoubleCheckVolatile.getInstance();
}
}
```
### 2.等待加载方式(不加锁)
利用java的类加载机制,保证了单例模式的准确性,由于static关键字,保证了初始化的单一性。
代码实现如下:
```java
/**
* 等待加载模式
*/
public class SingelazeHoder {
private SingelazeHoder() {
}
/**
* 内部私有类
*/
private static class InstanceHoderHelper{
private static final SingelazeHoder instance=new SingelazeHoder();
}
/**
* 获取单例元素
* @return 单例元素
*/
public static SingelazeHoder getInstance(){
return InstanceHoderHelper.instance;
}
/**
* 其他类引用时的使用方法
* @param args
*/
public static void main(String[] args) {
SingelazeHoder s=SingelazeHoder.getInstance();
}
}
```
### 3.利用枚举的方式实现
枚举类型是私有的,且为线程安全的,且在构造时,只会被装载一次,故能实现相关的单例模式。
```java
/**
* 利用枚举实现单例模式
*/
public class SingletonEnum {
private SingletonEnum(){}
//利用枚举
private enum Singleton {
INSTANCE;
private SingletonEnum instance=null;
Singleton(){
instance=new SingletonEnum();
}
public SingletonEnum getInstance() {
return instance;
}
}
//获取单例信息
public static SingletonEnum getInstance(){
return Singleton.INSTANCE.getInstance();
}
//其他类使用时调用方法
public static void main(String[] args) {
SingletonEnum s=SingletonEnum.getInstance();
}
}
``` 查看全部
# Java多线程相关知识【8】--设计模式--Singleton方式
## 一、四种单例模式(Singleton)的优缺点在多线程下
### 1.饿汉式
优点:实现简单。
缺点:使用前即主动加载,若很长时间未使用,易造成内存浪费。
代码实现如下所示:
```java
/**
* 饿汉式单例模式
*/
public class SingelazeHangers {
//创建类时即创建了元素
private static SingelazeHangers instance = new SingelazeHangers();
private SingelazeHangers() {
}
/**
* 真正执行时调用此元素
* @return 返回单例设计
*/
public static SingelazeHangers getInstance() {
return instance;
}
//测试实例加载
public static void main(String[] args) {
SingelazeHangers s=SingelazeHangers.getInstance();
}
}
```
### 2.懒汉式
优点:需要时才会加载,减少内存的浪费。
缺点:多个线程同时获取时,可能会被创建多次,易产生问题,可能不是单个实例。
```java
/**
* 懒汉式单例模式
*/
public class SingelazeLazyers {
//创建时并未创建类
public static SingelazeLazyers instance = null;
private SingelazeLazyers() {
}
/**
* 需要时进行类的创建
* @return 返回创建的结果
*/
public static SingelazeLazyers getInstance() {
if (instance == null)
instance = new SingelazeLazyers();
return instance;
}
//测试单例模式
public static void main(String[] args) {
SingelazeLazyers s=SingelazeLazyers.getInstance();
}
}
```
### 3.懒汉式改进
#### 1.函数加锁
优点:解决懒汉加载可能创建多个实例的问题。
缺点:性能低下。
说明:多线程使用时,虽然会解决创建非单例的问题,但是,在创建后,所有的线程依然需要进行等待,会浪费大量的时间进行单例的获取。
代码实现如下:
```java
/**
* 懒汉式单例模式(加类锁)
*/
public class SingelazeLazyersClassLock {
//创建时并未创建类
public static SingelazeLazyersClassLock instance = null;
private SingelazeLazyersClassLock() {
}
/**
* 需要时进行类的创建(关键字在此添加)
* @return 返回创建的结果
*/
public synchronized static SingelazeLazyersClassLock getInstance() {
if (instance == null)
instance = new SingelazeLazyersClassLock();
return instance;
}
//测试单例模式
public static void main(String[] args) {
SingelazeLazyersClassLock s= SingelazeLazyersClassLock.getInstance();
}
}
```
#### 2.双重判断
优点:解决函数加锁产生的性能问题。
缺点:易产生空指针异常。
说明:多线程使用时,第一个获取的元素释放了相关的锁,但是,对象内部的内容并未创建完成,导致其他线程调用到方法时,虽然拿到了对象,但对象内,需要使用的方法并未被实例化。
代码实现如下:
```java
/**
* 懒汉式单例模式(双重锁)
*/
public class SingelazeLazyersDoubleCheck {
//创建时并未创建类
public static SingelazeLazyersDoubleCheck instance = null;
private SingelazeLazyersDoubleCheck() {
}
/**
* 需要时进行类的创建(内容在此修改)
*
* @return 返回创建的结果
*/
public static SingelazeLazyersDoubleCheck getInstance() {
if (instance == null) {
synchronized (SingelazeLazyersDoubleCheck.class) {
if (instance == null)
instance = new SingelazeLazyersDoubleCheck();
}
}
return instance;
}
//测试单例模式
public static void main(String[] args) {
SingelazeLazyersDoubleCheck s = SingelazeLazyersDoubleCheck.getInstance();
}
}
```
## 二、三种优雅实现单例的方法
### 1.双重判断的改进
volatile关键字非原子性的,他可保证内存是可见的,并能够指定编译器及虚拟机不可对相关的语句进行优化,并保证在读相应内存区时,相关元素的创建必须完成。
缺点:虚拟机未优化,执行效率低下。
```java
/**
* 懒汉式单例模式(双重锁,内存可见式)
*/
public class SingelazeLazyersDoubleCheckVolatile {
//创建时并未创建类(关键字在此添加)
public volatile static SingelazeLazyersDoubleCheckVolatile instance = null;
private SingelazeLazyersDoubleCheckVolatile() {
}
/**
* 需要时进行类的创建
*
* @return 返回创建的结果
*/
public static SingelazeLazyersDoubleCheckVolatile getInstance() {
if (instance == null) {
synchronized (SingelazeLazyersDoubleCheckVolatile.class) {
if (instance == null)
instance = new SingelazeLazyersDoubleCheckVolatile();
}
}
return instance;
}
//测试单例模式
public static void main(String[] args) {
SingelazeLazyersDoubleCheckVolatile s = SingelazeLazyersDoubleCheckVolatile.getInstance();
}
}
```
### 2.等待加载方式(不加锁)
利用java的类加载机制,保证了单例模式的准确性,由于static关键字,保证了初始化的单一性。
代码实现如下:
```java
/**
* 等待加载模式
*/
public class SingelazeHoder {
private SingelazeHoder() {
}
/**
* 内部私有类
*/
private static class InstanceHoderHelper{
private static final SingelazeHoder instance=new SingelazeHoder();
}
/**
* 获取单例元素
* @return 单例元素
*/
public static SingelazeHoder getInstance(){
return InstanceHoderHelper.instance;
}
/**
* 其他类引用时的使用方法
* @param args
*/
public static void main(String[] args) {
SingelazeHoder s=SingelazeHoder.getInstance();
}
}
```
### 3.利用枚举的方式实现
枚举类型是私有的,且为线程安全的,且在构造时,只会被装载一次,故能实现相关的单例模式。
```java
/**
* 利用枚举实现单例模式
*/
public class SingletonEnum {
private SingletonEnum(){}
//利用枚举
private enum Singleton {
INSTANCE;
private SingletonEnum instance=null;
Singleton(){
instance=new SingletonEnum();
}
public SingletonEnum getInstance() {
return instance;
}
}
//获取单例信息
public static SingletonEnum getInstance(){
return Singleton.INSTANCE.getInstance();
}
//其他类使用时调用方法
public static void main(String[] args) {
SingletonEnum s=SingletonEnum.getInstance();
}
}
``` 查看全部
[TOC]
# Java多线程相关知识【8】--设计模式--Singleton方式
## 一、四种单例模式(Singleton)的优缺点在多线程下
### 1.饿汉式
优点:实现简单。
缺点:使用前即主动加载,若很长时间未使用,易造成内存浪费。
代码实现如下所示:
```java
/**
* 饿汉式单例模式
*/
public class SingelazeHangers {
//创建类时即创建了元素
private static SingelazeHangers instance = new SingelazeHangers();
private SingelazeHangers() {
}
/**
* 真正执行时调用此元素
* @return 返回单例设计
*/
public static SingelazeHangers getInstance() {
return instance;
}
//测试实例加载
public static void main(String[] args) {
SingelazeHangers s=SingelazeHangers.getInstance();
}
}
```
### 2.懒汉式
优点:需要时才会加载,减少内存的浪费。
缺点:多个线程同时获取时,可能会被创建多次,易产生问题,可能不是单个实例。
```java
/**
* 懒汉式单例模式
*/
public class SingelazeLazyers {
//创建时并未创建类
public static SingelazeLazyers instance = null;
private SingelazeLazyers() {
}
/**
* 需要时进行类的创建
* @return 返回创建的结果
*/
public static SingelazeLazyers getInstance() {
if (instance == null)
instance = new SingelazeLazyers();
return instance;
}
//测试单例模式
public static void main(String[] args) {
SingelazeLazyers s=SingelazeLazyers.getInstance();
}
}
```
### 3.懒汉式改进
#### 1.函数加锁
优点:解决懒汉加载可能创建多个实例的问题。
缺点:性能低下。
说明:多线程使用时,虽然会解决创建非单例的问题,但是,在创建后,所有的线程依然需要进行等待,会浪费大量的时间进行单例的获取。
代码实现如下:
```java
/**
* 懒汉式单例模式(加类锁)
*/
public class SingelazeLazyersClassLock {
//创建时并未创建类
public static SingelazeLazyersClassLock instance = null;
private SingelazeLazyersClassLock() {
}
/**
* 需要时进行类的创建(关键字在此添加)
* @return 返回创建的结果
*/
public synchronized static SingelazeLazyersClassLock getInstance() {
if (instance == null)
instance = new SingelazeLazyersClassLock();
return instance;
}
//测试单例模式
public static void main(String[] args) {
SingelazeLazyersClassLock s= SingelazeLazyersClassLock.getInstance();
}
}
```
#### 2.双重判断
优点:解决函数加锁产生的性能问题。
缺点:易产生空指针异常。
说明:多线程使用时,第一个获取的元素释放了相关的锁,但是,对象内部的内容并未创建完成,导致其他线程调用到方法时,虽然拿到了对象,但对象内,需要使用的方法并未被实例化。
代码实现如下:
```java
/**
* 懒汉式单例模式(双重锁)
*/
public class SingelazeLazyersDoubleCheck {
//创建时并未创建类
public static SingelazeLazyersDoubleCheck instance = null;
private SingelazeLazyersDoubleCheck() {
}
/**
* 需要时进行类的创建(内容在此修改)
*
* @return 返回创建的结果
*/
public static SingelazeLazyersDoubleCheck getInstance() {
if (instance == null) {
synchronized (SingelazeLazyersDoubleCheck.class) {
if (instance == null)
instance = new SingelazeLazyersDoubleCheck();
}
}
return instance;
}
//测试单例模式
public static void main(String[] args) {
SingelazeLazyersDoubleCheck s = SingelazeLazyersDoubleCheck.getInstance();
}
}
```
## 二、三种优雅实现单例的方法
### 1.双重判断的改进
volatile关键字非原子性的,他可保证内存是可见的,并能够指定编译器及虚拟机不可对相关的语句进行优化,并保证在读相应内存区时,相关元素的创建必须完成。
缺点:虚拟机未优化,执行效率低下。
```java
/**
* 懒汉式单例模式(双重锁,内存可见式)
*/
public class SingelazeLazyersDoubleCheckVolatile {
//创建时并未创建类(关键字在此添加)
public volatile static SingelazeLazyersDoubleCheckVolatile instance = null;
private SingelazeLazyersDoubleCheckVolatile() {
}
/**
* 需要时进行类的创建
*
* @return 返回创建的结果
*/
public static SingelazeLazyersDoubleCheckVolatile getInstance() {
if (instance == null) {
synchronized (SingelazeLazyersDoubleCheckVolatile.class) {
if (instance == null)
instance = new SingelazeLazyersDoubleCheckVolatile();
}
}
return instance;
}
//测试单例模式
public static void main(String[] args) {
SingelazeLazyersDoubleCheckVolatile s = SingelazeLazyersDoubleCheckVolatile.getInstance();
}
}
```
### 2.等待加载方式(不加锁)
利用java的类加载机制,保证了单例模式的准确性,由于static关键字,保证了初始化的单一性。
代码实现如下:
```java
/**
* 等待加载模式
*/
public class SingelazeHoder {
private SingelazeHoder() {
}
/**
* 内部私有类
*/
private static class InstanceHoderHelper{
private static final SingelazeHoder instance=new SingelazeHoder();
}
/**
* 获取单例元素
* @return 单例元素
*/
public static SingelazeHoder getInstance(){
return InstanceHoderHelper.instance;
}
/**
* 其他类引用时的使用方法
* @param args
*/
public static void main(String[] args) {
SingelazeHoder s=SingelazeHoder.getInstance();
}
}
```
### 3.利用枚举的方式实现
枚举类型是私有的,且为线程安全的,且在构造时,只会被装载一次,故能实现相关的单例模式。
```java
/**
* 利用枚举实现单例模式
*/
public class SingletonEnum {
private SingletonEnum(){}
//利用枚举
private enum Singleton {
INSTANCE;
private SingletonEnum instance=null;
Singleton(){
instance=new SingletonEnum();
}
public SingletonEnum getInstance() {
return instance;
}
}
//获取单例信息
public static SingletonEnum getInstance(){
return Singleton.INSTANCE.getInstance();
}
//其他类使用时调用方法
public static void main(String[] args) {
SingletonEnum s=SingletonEnum.getInstance();
}
}
```
Java多线程相关知识【5】--锁
micform-admin 发表了文章 • 0 个评论 • 1115 次浏览 • 2019-10-18 15:54
[TOC]
# Java多线程相关知识【5】--锁
菜鸟的一个学习笔记,欢迎大神<font color=red>批评指正</font>。
## 1. 使用synchronized关键字
### 1. 对变量进行加锁
```java
private final static Object object = new Object();
private void lockTest() {
synchronized (object) {
//do some
}
}
```
### 2. 对函数进行加锁
```java
private synchronized void lockTest2() {
//do some
}
```
### 3. 对类进行加锁
```java
private synchronized void lockTest3() {
synchronized (this) {
//do some
}
}
```
## 2. 自实现一个LOCK
### 锁接口
```java
/**
* 锁 提供功能
*/
public interface MyLock {
class TimeOutException extends Exception{
public TimeOutException(String message) {
super(message);
}
}
/**
* 加锁
* @throws InterruptedException
*/
void lock() throws InterruptedException;
/**
* 加锁
* @param times 锁的时间毫秒
* @throws InterruptedException
* @throws TimeOutException
*/
void lock(long times) throws InterruptedException,TimeOutException;
/**
* 解锁
*/
void unLock();
/**
* 获取锁住的线程
* @return
*/
Collection<Thread> getBlockThread();
/**
* 获取锁住的数目
* @return
*/
int getBlockSize();
}
```
### 锁实现
```java
/**
* 锁实现,实现锁的功能
*/
public class MyLockImpl implements MyLock {
private boolean initValue;
private Collection<Thread> threadCollection = new ArrayList<>();
private Thread thisThread;
public MyLockImpl() {
this.initValue = false;
}
@Override
public void lock() throws InterruptedException {
while (initValue) {
threadCollection.add(Thread.currentThread());
this.wait();
}
threadCollection.remove(Thread.currentThread());
this.initValue=true;
thisThread =Thread.currentThread();
}
@Override
public void lock(long times) throws InterruptedException, TimeOutException {
if (times<=0)
lock();
long hasTime=times;
long endTime=System.currentTimeMillis()+hasTime;
while (initValue) {
if (hasTime<=0)
throw new TimeOutException("Time Out!");
threadCollection.add(Thread.currentThread());
this.wait(times);
hasTime=endTime-System.currentTimeMillis();
}
threadCollection.remove(Thread.currentThread());
this.initValue=true;
thisThread =Thread.currentThread();
}
@Override
public void unLock() {
if (Thread.currentThread()==thisThread){
this.initValue=false;
Optional.ofNullable(Thread.currentThread().getName()+" unlock!")
.ifPresent(System.out::println);
this.notifyAll();
}
}
@Override
public Collection<Thread> getBlockThread() {
return threadCollection;
}
@Override
public int getBlockSize() {
return threadCollection.size();
}
}
``` 查看全部
# Java多线程相关知识【5】--锁
菜鸟的一个学习笔记,欢迎大神<font color=red>批评指正</font>。
## 1. 使用synchronized关键字
### 1. 对变量进行加锁
```java
private final static Object object = new Object();
private void lockTest() {
synchronized (object) {
//do some
}
}
```
### 2. 对函数进行加锁
```java
private synchronized void lockTest2() {
//do some
}
```
### 3. 对类进行加锁
```java
private synchronized void lockTest3() {
synchronized (this) {
//do some
}
}
```
## 2. 自实现一个LOCK
### 锁接口
```java
/**
* 锁 提供功能
*/
public interface MyLock {
class TimeOutException extends Exception{
public TimeOutException(String message) {
super(message);
}
}
/**
* 加锁
* @throws InterruptedException
*/
void lock() throws InterruptedException;
/**
* 加锁
* @param times 锁的时间毫秒
* @throws InterruptedException
* @throws TimeOutException
*/
void lock(long times) throws InterruptedException,TimeOutException;
/**
* 解锁
*/
void unLock();
/**
* 获取锁住的线程
* @return
*/
Collection<Thread> getBlockThread();
/**
* 获取锁住的数目
* @return
*/
int getBlockSize();
}
```
### 锁实现
```java
/**
* 锁实现,实现锁的功能
*/
public class MyLockImpl implements MyLock {
private boolean initValue;
private Collection<Thread> threadCollection = new ArrayList<>();
private Thread thisThread;
public MyLockImpl() {
this.initValue = false;
}
@Override
public void lock() throws InterruptedException {
while (initValue) {
threadCollection.add(Thread.currentThread());
this.wait();
}
threadCollection.remove(Thread.currentThread());
this.initValue=true;
thisThread =Thread.currentThread();
}
@Override
public void lock(long times) throws InterruptedException, TimeOutException {
if (times<=0)
lock();
long hasTime=times;
long endTime=System.currentTimeMillis()+hasTime;
while (initValue) {
if (hasTime<=0)
throw new TimeOutException("Time Out!");
threadCollection.add(Thread.currentThread());
this.wait(times);
hasTime=endTime-System.currentTimeMillis();
}
threadCollection.remove(Thread.currentThread());
this.initValue=true;
thisThread =Thread.currentThread();
}
@Override
public void unLock() {
if (Thread.currentThread()==thisThread){
this.initValue=false;
Optional.ofNullable(Thread.currentThread().getName()+" unlock!")
.ifPresent(System.out::println);
this.notifyAll();
}
}
@Override
public Collection<Thread> getBlockThread() {
return threadCollection;
}
@Override
public int getBlockSize() {
return threadCollection.size();
}
}
``` 查看全部
[TOC]
# Java多线程相关知识【5】--锁
菜鸟的一个学习笔记,欢迎大神<font color=red>批评指正</font>。
## 1. 使用synchronized关键字
### 1. 对变量进行加锁
```java
private final static Object object = new Object();
private void lockTest() {
synchronized (object) {
//do some
}
}
```
### 2. 对函数进行加锁
```java
private synchronized void lockTest2() {
//do some
}
```
### 3. 对类进行加锁
```java
private synchronized void lockTest3() {
synchronized (this) {
//do some
}
}
```
## 2. 自实现一个LOCK
### 锁接口
```java
/**
* 锁 提供功能
*/
public interface MyLock {
class TimeOutException extends Exception{
public TimeOutException(String message) {
super(message);
}
}
/**
* 加锁
* @throws InterruptedException
*/
void lock() throws InterruptedException;
/**
* 加锁
* @param times 锁的时间毫秒
* @throws InterruptedException
* @throws TimeOutException
*/
void lock(long times) throws InterruptedException,TimeOutException;
/**
* 解锁
*/
void unLock();
/**
* 获取锁住的线程
* @return
*/
Collection<Thread> getBlockThread();
/**
* 获取锁住的数目
* @return
*/
int getBlockSize();
}
```
### 锁实现
```java
/**
* 锁实现,实现锁的功能
*/
public class MyLockImpl implements MyLock {
private boolean initValue;
private Collection<Thread> threadCollection = new ArrayList<>();
private Thread thisThread;
public MyLockImpl() {
this.initValue = false;
}
@Override
public void lock() throws InterruptedException {
while (initValue) {
threadCollection.add(Thread.currentThread());
this.wait();
}
threadCollection.remove(Thread.currentThread());
this.initValue=true;
thisThread =Thread.currentThread();
}
@Override
public void lock(long times) throws InterruptedException, TimeOutException {
if (times<=0)
lock();
long hasTime=times;
long endTime=System.currentTimeMillis()+hasTime;
while (initValue) {
if (hasTime<=0)
throw new TimeOutException("Time Out!");
threadCollection.add(Thread.currentThread());
this.wait(times);
hasTime=endTime-System.currentTimeMillis();
}
threadCollection.remove(Thread.currentThread());
this.initValue=true;
thisThread =Thread.currentThread();
}
@Override
public void unLock() {
if (Thread.currentThread()==thisThread){
this.initValue=false;
Optional.ofNullable(Thread.currentThread().getName()+" unlock!")
.ifPresent(System.out::println);
this.notifyAll();
}
}
@Override
public Collection<Thread> getBlockThread() {
return threadCollection;
}
@Override
public int getBlockSize() {
return threadCollection.size();
}
}
```
Java多线程相关知识【4】--线程同步
micform-admin 发表了文章 • 0 个评论 • 1106 次浏览 • 2019-10-18 15:50
# Java多线程相关知识【4】--线程同步
菜鸟的一个学习笔记,欢迎大神<font color=red>批评指正</font>。
## 利用join()使多个线程同步
```java
Thread t1 = new Thread(() -> {
try {
Thread.sleep(RANDOM.nextInt(1000));
System.out.println(Thread.currentThread().getName() + " finished!");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
Thread.sleep(RANDOM.nextInt(1000));
System.out.println(Thread.currentThread().getName() + " finished!");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("同步后执行");
``` 查看全部
菜鸟的一个学习笔记,欢迎大神<font color=red>批评指正</font>。
## 利用join()使多个线程同步
```java
Thread t1 = new Thread(() -> {
try {
Thread.sleep(RANDOM.nextInt(1000));
System.out.println(Thread.currentThread().getName() + " finished!");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
Thread.sleep(RANDOM.nextInt(1000));
System.out.println(Thread.currentThread().getName() + " finished!");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("同步后执行");
``` 查看全部
# Java多线程相关知识【4】--线程同步
菜鸟的一个学习笔记,欢迎大神<font color=red>批评指正</font>。
## 利用join()使多个线程同步
```java
Thread t1 = new Thread(() -> {
try {
Thread.sleep(RANDOM.nextInt(1000));
System.out.println(Thread.currentThread().getName() + " finished!");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
Thread.sleep(RANDOM.nextInt(1000));
System.out.println(Thread.currentThread().getName() + " finished!");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("同步后执行");
```
Java多线程相关知识【2】--Thread的构造方法
micform-admin 发表了文章 • 0 个评论 • 1080 次浏览 • 2019-10-18 15:47
Java多线程相关知识【2】--Thread的构造方法
菜鸟的一个学习笔记,大神请绕路。
一、Thread()
新建一个线程,这个线程,若未手动实现他的run方法,他将什么也不干。
Thread() 的使用方法通常是:Thread a = new Thread(){ @Override public void run() { // do some thing } };二、Thread(Runnable target)
新建一个线程,这个线程将运行Runnable中的run方法。
Thread(Runnable target)的使用方法通常是: Runnable runnable=new Runnable() { @Override public void run() { // do some thing } }; Thread tRunnable=new Thread(runnable);在java8中,可以使用lambda表达式将以上内容简化: Thread tRL=new Thread(()->{ //do some thing });此方法的实现原理:
将Runnable的run方法保存,在运行时,虚拟机将自动调用Runnable的run()方法。
三、Thread(String name)
为运行的线程标记一个名字,若未标记,则会使用Thread+当前序号来进行名称的标识。
四、Thread(Runnable target, String name)
同上三四两点的结合。
五、Thread(ThreadGroup group, Runnable target)
将线程加入一个线程组中,默认加入的线程组为main。
六、Thread(ThreadGroup group, Runnable target, String name)
将线程加入一个线程组中,默认加入的线程组为main,并设置线程名字。
七、Thread(ThreadGroup group, Runnable target, String name, long stackSize)
将线程加入一个线程组中,默认加入的线程组为main,并设置线程名字,并设置其最大栈深度,~ 默认深度为随机的(不确定)。
八、Thread(ThreadGroup group, String name)
线程组
可将多个线程放入的一个容器。
构造方法
1. ThreadGroup(String name)
创建一个线程组并设置这个线程组的名称。
2. ThreadGroup(ThreadGroup parent, String name)
创建一个线程组,设置这个线程组的父线程组,并设置这个线程组的名称。
函数含义
将线程加入一个线程组中,默认加入的线程组为main,并设置线程名字。
查看全部
菜鸟的一个学习笔记,大神请绕路。
一、Thread()
新建一个线程,这个线程,若未手动实现他的run方法,他将什么也不干。
Thread() 的使用方法通常是:Thread a = new Thread(){ @Override public void run() { // do some thing } };二、Thread(Runnable target)
新建一个线程,这个线程将运行Runnable中的run方法。
Thread(Runnable target)的使用方法通常是: Runnable runnable=new Runnable() { @Override public void run() { // do some thing } }; Thread tRunnable=new Thread(runnable);在java8中,可以使用lambda表达式将以上内容简化: Thread tRL=new Thread(()->{ //do some thing });此方法的实现原理:
将Runnable的run方法保存,在运行时,虚拟机将自动调用Runnable的run()方法。
三、Thread(String name)
为运行的线程标记一个名字,若未标记,则会使用Thread+当前序号来进行名称的标识。
四、Thread(Runnable target, String name)
同上三四两点的结合。
五、Thread(ThreadGroup group, Runnable target)
将线程加入一个线程组中,默认加入的线程组为main。
六、Thread(ThreadGroup group, Runnable target, String name)
将线程加入一个线程组中,默认加入的线程组为main,并设置线程名字。
七、Thread(ThreadGroup group, Runnable target, String name, long stackSize)
将线程加入一个线程组中,默认加入的线程组为main,并设置线程名字,并设置其最大栈深度,~ 默认深度为随机的(不确定)。
八、Thread(ThreadGroup group, String name)
线程组
可将多个线程放入的一个容器。
构造方法
1. ThreadGroup(String name)
创建一个线程组并设置这个线程组的名称。
2. ThreadGroup(ThreadGroup parent, String name)
创建一个线程组,设置这个线程组的父线程组,并设置这个线程组的名称。
函数含义
将线程加入一个线程组中,默认加入的线程组为main,并设置线程名字。
查看全部
Java多线程相关知识【2】--Thread的构造方法
菜鸟的一个学习笔记,大神请绕路。
一、Thread()
新建一个线程,这个线程,若未手动实现他的run方法,他将什么也不干。
Thread() 的使用方法通常是:Thread a = new Thread(){ @Override public void run() { // do some thing } };二、Thread(Runnable target)
新建一个线程,这个线程将运行Runnable中的run方法。
Thread(Runnable target)的使用方法通常是: Runnable runnable=new Runnable() { @Override public void run() { // do some thing } }; Thread tRunnable=new Thread(runnable);在java8中,可以使用lambda表达式将以上内容简化: Thread tRL=new Thread(()->{ //do some thing });此方法的实现原理:
将Runnable的run方法保存,在运行时,虚拟机将自动调用Runnable的run()方法。
三、Thread(String name)
为运行的线程标记一个名字,若未标记,则会使用Thread+当前序号来进行名称的标识。
四、Thread(Runnable target, String name)
同上三四两点的结合。
五、Thread(ThreadGroup group, Runnable target)
将线程加入一个线程组中,默认加入的线程组为main。
六、Thread(ThreadGroup group, Runnable target, String name)
将线程加入一个线程组中,默认加入的线程组为main,并设置线程名字。
七、Thread(ThreadGroup group, Runnable target, String name, long stackSize)
将线程加入一个线程组中,默认加入的线程组为main,并设置线程名字,并设置其最大栈深度,~ 默认深度为随机的(不确定)。
八、Thread(ThreadGroup group, String name)
线程组
可将多个线程放入的一个容器。
构造方法
1. ThreadGroup(String name)
创建一个线程组并设置这个线程组的名称。
2. ThreadGroup(ThreadGroup parent, String name)
创建一个线程组,设置这个线程组的父线程组,并设置这个线程组的名称。
函数含义
将线程加入一个线程组中,默认加入的线程组为main,并设置线程名字。
菜鸟的一个学习笔记,大神请绕路。
一、Thread()
新建一个线程,这个线程,若未手动实现他的run方法,他将什么也不干。
Thread() 的使用方法通常是:Thread a = new Thread(){ @Override public void run() { // do some thing } };二、Thread(Runnable target)
新建一个线程,这个线程将运行Runnable中的run方法。
Thread(Runnable target)的使用方法通常是: Runnable runnable=new Runnable() { @Override public void run() { // do some thing } }; Thread tRunnable=new Thread(runnable);在java8中,可以使用lambda表达式将以上内容简化: Thread tRL=new Thread(()->{ //do some thing });此方法的实现原理:
将Runnable的run方法保存,在运行时,虚拟机将自动调用Runnable的run()方法。
三、Thread(String name)
为运行的线程标记一个名字,若未标记,则会使用Thread+当前序号来进行名称的标识。
四、Thread(Runnable target, String name)
同上三四两点的结合。
五、Thread(ThreadGroup group, Runnable target)
将线程加入一个线程组中,默认加入的线程组为main。
六、Thread(ThreadGroup group, Runnable target, String name)
将线程加入一个线程组中,默认加入的线程组为main,并设置线程名字。
七、Thread(ThreadGroup group, Runnable target, String name, long stackSize)
将线程加入一个线程组中,默认加入的线程组为main,并设置线程名字,并设置其最大栈深度,~ 默认深度为随机的(不确定)。
八、Thread(ThreadGroup group, String name)
线程组
可将多个线程放入的一个容器。
构造方法
1. ThreadGroup(String name)
创建一个线程组并设置这个线程组的名称。
2. ThreadGroup(ThreadGroup parent, String name)
创建一个线程组,设置这个线程组的父线程组,并设置这个线程组的名称。
函数含义
将线程加入一个线程组中,默认加入的线程组为main,并设置线程名字。
Java多线程相关知识【1】--新建线程
micform-admin 发表了文章 • 0 个评论 • 1317 次浏览 • 2019-10-18 15:45
Java多线程相关知识【1】--新建线程
菜鸟的一个学习笔记,大神请绕路。
一、extend (继承Thread类)
新建一个thread,并重写其中的run方法
public class ExtendThread extends Thread { @Override public void run() { //do something } }
将继承的类实例化
Thread myThread = new ExtendThread();
调用实例化对象启动线程
myThread.start();
二、implements (实现Runnable接口)
实现implements接口,并实现其中的run方法
public class ImplementsThread implements Runnable { public void run() { //do something } }
使用thread方法,并将接口实例化的结果作为thread的参数传入thread方法,初始化线程
Thread myThread=new Thread(new ImplementsThread());
调用实例化对象启动线程
myThread.start();
知道如何新建线程了,接下来我们将深入的理解Thread的构造方法 查看全部
菜鸟的一个学习笔记,大神请绕路。
一、extend (继承Thread类)
新建一个thread,并重写其中的run方法
public class ExtendThread extends Thread { @Override public void run() { //do something } }
将继承的类实例化
Thread myThread = new ExtendThread();
调用实例化对象启动线程
myThread.start();
二、implements (实现Runnable接口)
实现implements接口,并实现其中的run方法
public class ImplementsThread implements Runnable { public void run() { //do something } }
使用thread方法,并将接口实例化的结果作为thread的参数传入thread方法,初始化线程
Thread myThread=new Thread(new ImplementsThread());
调用实例化对象启动线程
myThread.start();
知道如何新建线程了,接下来我们将深入的理解Thread的构造方法 查看全部
Java多线程相关知识【1】--新建线程
菜鸟的一个学习笔记,大神请绕路。
一、extend (继承Thread类)
新建一个thread,并重写其中的run方法
public class ExtendThread extends Thread { @Override public void run() { //do something } }
将继承的类实例化
Thread myThread = new ExtendThread();
调用实例化对象启动线程
myThread.start();
二、implements (实现Runnable接口)
实现implements接口,并实现其中的run方法
public class ImplementsThread implements Runnable { public void run() { //do something } }
使用thread方法,并将接口实例化的结果作为thread的参数传入thread方法,初始化线程
Thread myThread=new Thread(new ImplementsThread());
调用实例化对象启动线程
myThread.start();
知道如何新建线程了,接下来我们将深入的理解Thread的构造方法
菜鸟的一个学习笔记,大神请绕路。
一、extend (继承Thread类)
新建一个thread,并重写其中的run方法
public class ExtendThread extends Thread { @Override public void run() { //do something } }
将继承的类实例化
Thread myThread = new ExtendThread();
调用实例化对象启动线程
myThread.start();
二、implements (实现Runnable接口)
实现implements接口,并实现其中的run方法
public class ImplementsThread implements Runnable { public void run() { //do something } }
使用thread方法,并将接口实例化的结果作为thread的参数传入thread方法,初始化线程
Thread myThread=new Thread(new ImplementsThread());
调用实例化对象启动线程
myThread.start();
知道如何新建线程了,接下来我们将深入的理解Thread的构造方法