Java多线程相关知识【10】--解释volatile关键字

micform-admin 发表了文章 • 0 个评论 • 137 次浏览 • 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. 需要保证关键字修饰的语句的执行的先后顺序不发送改变,即运行一致性时,可使用本关键字。 查看全部
# 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 个评论 • 150 次浏览 • 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();
``` 查看全部
[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 个评论 • 152 次浏览 • 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();
}
}

``` 查看全部
[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 个评论 • 214 次浏览 • 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();
}
}
``` 查看全部
[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 个评论 • 172 次浏览 • 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("同步后执行");
``` 查看全部
# 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 个评论 • 154 次浏览 • 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,并设置线程名字。
  查看全部
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,并设置线程名字。
 

Java多线程相关知识【1】--新建线程

micform-admin 发表了文章 • 0 个评论 • 126 次浏览 • 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的构造方法 查看全部
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的构造方法