Skip to content

Commit f6c05e8

Browse files
committed
08-02
1 parent 7ddd63e commit f6c05e8

File tree

3 files changed

+286
-0
lines changed

3 files changed

+286
-0
lines changed

_posts/2019-08-01-Synchronized.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
---
2+
layout: post
3+
title: Synchronized 和 volatile
4+
description: java关键字Synchronized he volation介绍
5+
tag: javase
6+
---
7+
8+
# java关键字Synchronized 和 volatile
9+
10+
### 前提我们得搞清楚三个性质
11+
12+
##### 可见性:
13+
14+
​ 可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。也就是一个线程修改的结果。另一个线程马上就能看到。比如:用volatile修饰的变量,就会具有可见性。volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存。所以对其他线程是可见的。
15+
16+
##### 原子性:
17+
18+
​ 可以简单的理解为是不能被分割的,例如:int a = 0;这个操作不能被分割,具有原子性,这个操作被称为原子操作。例如:a++;实际操作是a=a+1;是可分割的,所以他不是一个原子操作。非原子操作都会存在线程安全问题,需要我们使用同步技术(sychronized)来让它变成一个原子操作。非原子操作不能包装线程安全。
19+
20+
##### 有序性
21+
22+
​ Java语言提供了volatile和synchronized两个关键字来保证线程之间操作的有序性,volatile是因为其本身包含“禁止指令重排序”的语义,synchronized是由“一个变量在同一个时刻只允许一条线程对其进行lock操作”这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。
23+
24+
### Synchronized
25+
26+
### **用法**
27+
28+
**synchronized可以用了修饰一个普通方法,或者代码块**,这个时候synchronized锁定的是当前对象,只要有一个线程在访问对应的方法或代码块,其他线程必须等待。
29+
30+
**synchronized只对修饰的方法有效**,锁定对象的其他非synchronized方法还是可以访问的
31+
32+
**synchronized也可以用来锁定指定对象**,当一个线程访问指定对象时,其他试图访问指定对象的线程将会阻塞,直到该线程访问指定对象结束
33+
34+
**synchronized可以用了修饰一个静态方法**,静态方法是属于类的而不属于对象的。同样的,synchronized修饰的静态方法锁定的是这个类的所有对象
35+
36+
**synchronized(*.class)效果跟锁定静态方法相同,都是锁定这个类的所有对象**
37+
38+
**注意**:实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
39+
40+
#### 实现原理:
41+
42+
1. 依赖 `JVM` 实现同步
43+
2. 底层通过一个监视器对象`(monitor)`完成, `wait()``notify()` 等方法也依赖于 monitor 对象
44+
45+
#### synchronized代码案例
46+
47+
```java
48+
public class Test{
49+
// 对象锁:形式1(方法锁)
50+
public synchronized void Method1(){
51+
System.out.println("我是对象锁也是方法锁");
52+
try{
53+
Thread.sleep(500);
54+
} catch (InterruptedException e){
55+
e.printStackTrace();
56+
}
57+
58+
}
59+
60+
// 对象锁:形式2(代码块形式)
61+
public void Method2(){
62+
synchronized (this){
63+
System.out.println("我是对象锁");
64+
try{
65+
Thread.sleep(500);
66+
} catch (InterruptedException e){
67+
e.printStackTrace();
68+
}
69+
}
70+
71+
}
72+
73+
/**
74+
* 类锁
75+
*/
76+
public class Test{
77+
   // 类锁:形式1 :锁静态方法
78+
public static synchronized void Method1(){
79+
System.out.println("我是类锁一号");
80+
try{
81+
Thread.sleep(500);
82+
} catch (InterruptedException e){
83+
e.printStackTrace();
84+
}
85+
86+
}
87+
88+
// 类锁:形式2 :锁静态代码块
89+
public void Method2(){
90+
synchronized (Test.class){
91+
System.out.println("我是类锁二号");
92+
try{
93+
Thread.sleep(500);
94+
} catch (InterruptedException e){
95+
e.printStackTrace();
96+
}
97+
98+
}
99+
100+
}
101+
102+
```
103+
104+
105+
106+
### volatile
107+
108+
Java语言提供了一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程。当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。
109+
110+
 当对非 volatile 变量进行读写的时候,每个线程先从内存拷贝变量到CPU缓存中。如果计算机有多个CPU,每个线程可能在不同的CPU上被处理,这意味着每个线程可以拷贝到不同的 CPU cache 中。
111+
112+
![](C:\Users\zh\Desktop\volatile.png)
113+
114+
  而声明变量是 volatile 的,JVM 保证了每次读变量都从内存中读,跳过 CPU cache 这一步。
115+
116+
需要注意的是volatile只能保证变量的原子性,但不能保证对变量操作的原子性
117+
118+
```java
119+
public class Volatiletest extends Thread{
120+
//public static volatile boolean flag = false;//不用该关键字此程序无限循环
121+
public static boolean flag = false;//用此关键字,会跳出循环
122+
123+
@Override
124+
public void run() {
125+
// TODO Auto-generated method stub
126+
while(!flag) {
127+
128+
}
129+
}
130+
131+
public static void main(String[] args) throws InterruptedException {
132+
new Volatiletest().start();
133+
Thread.sleep(2000);
134+
flag = true;
135+
}
136+
```
137+

_posts/2019-08-02-Thread.md

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
---
2+
layout: post
3+
title: 线程和进程
4+
description: 关于java线程和进程的介绍
5+
tag: javase
6+
---
7+
8+
# java线程和进程
9+
10+
### 进程
11+
12+
**进程就是一个执行中的程序实例**,每个进程都有自己独立的一块内存空间,一个进程中可以有多个线程。比如在Windows系统中,一个运行的xx.exe就是一个进程。每个进程有各自独立的一块内存,使得各个进程之间内存地址相互隔离。
13+
14+
进程可分为3个状态:就绪、执行、和阻塞
15+
16+
**就绪状态**(ready) : 当进程已分配到除CPU以外的所有必要资源后,只要在获得CPU,便可立即执行,进程这时的状态就称为就绪状态。在一个系统中处于就绪状态的进程可能有多个,通常将他们排成一个队列,称为就绪队列。
17+
18+
**执行状态**: 进程已获得CPU,其程序正在执行。在单处理机系统中,只有一个进程处于执行状态;再多处理机系统中,则有多个进程处于执行状态
19+
20+
**阻塞状态**: 正在执行的进程由于发生某事件而暂时无法继续执行时,便放弃处理机而处于暂停状态,亦即程序的执行受到阻塞,把这种暂停状态称为阻塞状态,有时也称为等待状态或封锁状态。
21+
22+
其转换图如下:
23+
24+
![](C:\Users\zh\Desktop\线程1.png)
25+
26+
### 线程
27+
28+
线程是指进程中的一个执行任务(控制单元),一个进程中可以运行多个线程。有如下几个特点:
29+
30+
1)进程中负责程序执行的执行单元
31+
32+
2)依靠程序执行的顺序控制流,只能使用程序的资源和环境,共享进程的全部资源
33+
34+
3)有自己的堆栈和局部变量,没有单独的地址空间
35+
36+
4)CPU调度和分派的基本单位,持有程序计数器,寄存器,堆栈
37+
38+
#### java线程中共有如下几个状态:
39+
40+
**New(新生)**
41+
NEW(新建尚未运行/启动)
42+
43+
**Runnable(可运行)**
44+
处于可运行状态:正在运行*或准备运行*
45+
在线程对象上调用start方法后,相应线程便会进入Runnable状态,若被线程调度程序调度,这个线程便会成为当前运行(Running)的线程;
46+
47+
**Blocked(被阻塞)**
48+
阻塞状态,受阻塞并等待某个监视器锁的线程,处于这种状态。
49+
若一段代码被线程A “上锁” ,此时线程B尝试执行这段代码,线程B就会进入Blocked状态;
50+
51+
**Waiting(等待)**
52+
通过wait方法进入的等待
53+
当线程等待另一个线程通知线程调度器一个条件时,它本身就会进入Waiting状态;
54+
55+
**Time Waiting(计时等待也被称为阻塞)**
56+
通过sleep或wait timeout方法进入的限期等待的状态
57+
计时等待与等待的区别是,线程只等待一定的时间,若超时则不再等待;
58+
59+
**Terminated(被终止)**
60+
线程终止状态
61+
线程的run方法执行完毕或者由于一个未捕获的异常导致run方法意外终止会进入Terminated状态。
62+
63+
来张更直观的图
64+
65+
![](C:\Users\zh\Desktop\线程2.png)
66+
67+
#### 关于一些控制线程的方法
68+
69+
#### start():
70+
71+
这是一个实例方法,启动一个线程,但是线程不是已启动就会执行,需要等待程序调度获得处理器资源。
72+
73+
**isAlive()**:
74+
75+
这是一个实例方法,判断一个线程是否还活着。
76+
77+
**sleep()**:
78+
79+
这是一个静态方法,使一个线程进入阻塞(等待)状态
80+
81+
**join()**
82+
83+
这是一个实例方法,在A线程中对线程B调用join方法会导致A线程暂时处于waiting,等线程B运行完毕后再接着运行线程A。
84+
也就是说,把当前线程还没执行的部分“接到”另一个线程后面去,另一个线程运行完毕后,当前线程再接着运行。
85+
86+
**yield()**:
87+
88+
这是一个静态方法,作用是让当前线程“让步”,目的是让其他线程有更大的可能被系统调度,这个方法不会释放锁。
89+
90+
yield() 的“让步”只是让一小会,一小会之后就接着工作了。
91+
yield操作时,线程还是Runnable状态。
92+

_posts/2019-08-02-offer01.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
layout: post
3+
title: offer01
4+
description: 剑指offer算法题
5+
tag: offer
6+
---
7+
8+
# 剑指offer算法题01
9+
10+
在一个二维数组中,每个一维数组相同,每一行从左到右为递增的序列排序,每一列从上到下递增的序列排序,实现一个方法,输入这样的一个数组和一个整数,并判断该数组中是否包含这个整数。
11+
12+
## 解题思路:
13+
14+
**第一种**:由于该数组的每一行都是递增的,我们可以遍历这个数组的每一行,在每一行中使用二分查找法,诺找到返回true,否则返回true
15+
16+
```java
17+
public static boolean findnum1(int[][] arr,int value) {
18+
19+
for(int i=0;i<arr.length;i++) {
20+
int low = 0;
21+
int high = arr[i].length-1;
22+
while(low<=high) {
23+
int mid = (low+high)/2;
24+
if(value==arr[i][mid]) {
25+
26+
return true;
27+
}else if(value>arr[i][mid]) {
28+
low=mid+1;
29+
}else {
30+
high=mid-1;
31+
}
32+
}
33+
}
34+
35+
return false;
36+
```
37+
38+
**第二种**:由于该数组行和列都是递增的,那么我们可以选取右上角的值拿来和关键字进行比较,若关键字大,则要找的自必定在右上角的下方,将row++继续比较。若关键字小,则必定在右上角的左方,将col--在继续比较。
39+
40+
```java
41+
public static boolean findnum12(int[][] arr,int value) {
42+
int row = 0;
43+
int col = arr[0].length-1;
44+
while(row<=arr.length-1&&col>=0) {
45+
if(value==arr[row][col]) {
46+
return true;
47+
}else if(value<arr[row][col]) {
48+
col--;
49+
}else {
50+
row++;
51+
}
52+
}
53+
return false;
54+
}
55+
56+
```
57+

0 commit comments

Comments
 (0)