前言
本篇博客主要總結了,多線程與高併發相關知識,目的是提升自己技術能力同時也能幫助你。
1.線程中的run與start的區別
package com.zcw.demo.demo1;
import java.util.concurrent.TimeUnit;
/**
* @ClassName : ZCWThread
* @Description :線程中start 方法與run方法
* @Author : Zhaocunwei
* @Date: 2020-06-13 13:39
*/
public class ZCWThread {
private static class T1 extends Thread{
@Override
public void run(){
for(int i=0;i<10;i++){
try {
TimeUnit.MICROSECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("T1");
}
}
}
public static void main(String[] args) {
new T1().start();
// new T1().run();
for(int i=0;i<10;i++){
try {
TimeUnit.MICROSECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main");
}
}
}
運行結果:
通過上面兩個圖分析原因,當我們調用start方法時,會在調用start方法那裏產生分支,這個分支和我的主程序一起執行,run方法呢,就一個執行路徑。
2.創建線程的兩種方式-啓動線程程序的三種方式
package com.zcw.demo.demo1;
/**
* @ClassName : HowToCreateThread
* @Description :創建線程的兩種方式
* @Author : Zhaocunwei
* @Date: 2020-06-13 14:15
*/
public class HowToCreateThread {
static class MyThread extends Thread{
@Override
public void run (){
System.out.println("Hello MyThread!");
}
static class MyRun implements Runnable{
@Override
public void run(){
System.out.println("Hello MyRun!");
}
public static void main(String[] args) {
new MyThread().start();
new Thread(new MyRun()).start();
new Thread(() ->{
System.out.println("Hello lambda!");
}).start();
}
}
}
}
啓動線程的三種方式:
1.Thread
2.Runnable
3.Executors.newCachedThrad
3.線程中的基本方法
package com.zcw.demo.demo1;
/**
* @ClassName : Sleep_yield_Join
* @Description :線程中的基本方法
* @Author : Zhaocunwei
* @Date: 2020-06-13 14:24
*/
public class Sleep_yield_Join {
public static void main(String[] args){
//testSleep();
//testYield();
//testJoin();
}
static void testSleep(){
new Thread(()->{
for(int i=0;i<100;i++){
System.out.println("A"+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
static void testYield(){
new Thread(()->{
for(int i=0;i<100;i++){
System.out.println("A"+i);
}
}).start();
new Thread(()->{
for(int i=0;i<100;i++){
System.out.println("------------------------B"+i);
if(i%10 == 0){
Thread.yield();
}
}
}).start();
}
static void testJoin(){
Thread t1= new Thread(()->{
for(int i=0;i<100;i++){
System.out.println("A"+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t2 = new Thread(() ->{
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0; i<100; i++){
System.out.println("A"+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
t2.start();
}
}
- 線程狀態
package com.zcw.demo.demo1;
/**
* @ClassName : ThreadState
* @Description :
* @Author : Zhaocunwei
* @Date: 2020-06-13 14:54
*/
public class ThreadState {
static class MyThread extends Thread{
@Override
public void run(){
System.out.println(this.getState());
for (int i=0;i<10;i++){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(i);
}
}
}
public static void main(String[] args) {
Thread t = new MyThread();
System.out.println(t.getState());
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getState());
}
}
4.Synchronized關鍵字對某個對象加鎖
package com.zcw.demo.demo1;
/**
* @ClassName : MySynchronized
* @Description : Synchronized關鍵字對某個對象加鎖
* @Author : Zhaocunwei
* @Date: 2020-06-13 15:20
*/
public class MySynchronized {
private static int count=10;
private Object o = new Object();
public void m(){
//任何線程要執行下面的代碼,必須先拿到0的項
synchronized (o){
count --;
System.out.println(Thread.currentThread().getName()+" count="+count);
}
}
//考慮一下這裏? synchronized(this)是否可以?
public static void mm(){
synchronized (MySynchronized.class){
count --;
}
}
}
- synchronized(Object)不能用String,常量,Integer long
- 線程同步
synchronized
1.鎖的是對象不是代碼
2.this xxx.class
3鎖定方法,非鎖定方法同時執行。
4.鎖升級: 偏向鎖,自旋鎖,重量級鎖,線程數少,自旋鎖多。
操作消耗時間長,重量級鎖
5.Volatile
- 保證線程可見性
- 禁止指令重排序
– DCL單例
–Double Check Lock
–Mgr06.java
package com.zcw.demo.demo2;
import java.util.concurrent.TimeUnit;
/**
* @ClassName : T
* @Description :
* @Author : Zhaocunwei
* @Date: 2020-06-15 12:22
*/
public class T {
/**volatile**/ boolean running =true;//對比一下在volatile的情況下,整個程序運行結果的區別
void m(){
System.out.println("m start");
while(running){
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("m end");
}
public static void main(String[] args) {
T t = new T();
new Thread(t::m,"t1").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
t.running=false;
}
}
- 運行結果:
m start
m end
- 單例
餓漢式:
類加載到內存中後,就實例化一個單例,JVM保證線程安全,簡單實用,推薦使用,但是它的缺點是,不管用與否,類裝載時就實例化,Class.forName("")
package com.zcw.demo.demo2;
/**
* @ClassName : Mgro1
* @Description :餓漢式
* @Author : Zhaocunwei
* @Date: 2020-06-15 12:44
*/
public class Mgro1 {
private static final Mgro1 INSTANCE = new Mgro1();
private Mgro1(){};
public static Mgro1 getInstance(){
return INSTANCE;
}
public void m(){
System.out.println("m");
}
public static void main(String[] args) {
Mgro1 m1 = Mgro1.getInstance();
Mgro1 m2 =Mgro1.getInstance();
System.out.println(m1==m2);
}
}
- 運行結果:
true
- 懶漢式
1.線程不安全的
package com.zcw.demo.demo2;
/**
* @ClassName : Mgr03
* @Description :
* @Author : Zhaocunwei
* @Date: 2020-06-15 12:50
*/
public class Mgr03 {
private static Mgr03 INSTANCE;
private Mgr03(){
}
public static Mgr03 getInstance(){
if(INSTANCE == null){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE= new Mgr03();
}
return INSTANCE;
}
public void m(){
System.out.println("m");
}
public static void main(String[] args) {
for(int i=0; i<10;i++){
new Thread(()->
System.out.println(Mgr03.getInstance().hashCode())
).start();
}
}
}
- 運行結果:
1899625310
524631667
860147208
653846628
101695638
315181923
810466593
319155376
1035305589
1035305589
把上面的類創建爲線程安全的:
package com.zcw.demo.demo2;
/**
* @ClassName : Mgr04
* @Description : lazy loading
* 也稱爲懶漢式
* 雖然達到了按需初始化的目的,但是帶來了線程不安全的問題,
* 可以通過synchronized解決,但也帶來效率下降
* @Author : Zhaocunwei
* @Date: 2020-06-15 12:55
*/
public class Mgr04 {
private static Mgr04 INSTANCE;
private Mgr04(){
}
public static synchronized Mgr04 getInstance(){
if(INSTANCE == null){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr04();
}
return INSTANCE;
}
public void m(){
System.out.println("m");
}
public static void main(String[] args) {
for(int i =0;i<10;i++){
new Thread(()->{
System.out.println(Mgr04.getInstance().hashCode());
}).start();
}
}
}
- 運行結果:
554241184
554241184
554241184
554241184
554241184
554241184
554241184
554241184
554241184
554241184
- 單例模式添加volatile解決指令重排序問題
package com.zcw.demo.demo2;
/**
* @ClassName : Mgr06
* @Description :
* @Author : Zhaocunwei
* @Date: 2020-06-15 13:11
*/
public class Mgr06 {
private static volatile Mgr06 INSTANCE;
private Mgr06(){
}
public static Mgr06 getInstance(){
if(INSTANCE ==null){
synchronized (Mgr06.class){
if(INSTANCE ==null){
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
INSTANCE = new Mgr06();
}
}
}
return INSTANCE;
}
public void m(){
System.out.println("m");
}
public static void main(String[] args) {
for(int i=0;i<100;i++){
new Thread(()->{
System.out.println(Mgr06.getInstance().hashCode());
}).start();
}
}
}
- 運行結果:
315181923
315181923
315181923
315181923
315181923
315181923
... ...
5.CAS(無鎖優化 自旋)
- Compare And Swap
- 原子性
package com.zcw.demo.demo2;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @ClassName : AtomicInteger
* @Description :
* @Author : Zhaocunwei
* @Date: 2020-06-15 13:48
*/
public class MyAtomicInteger {
AtomicInteger count = new AtomicInteger(0);
void m(){
for(int i=0;i<1000;i++){
count.incrementAndGet();
}
}
public static void main(String[] args) {
MyAtomicInteger t = new MyAtomicInteger();
List<Thread> threads = new ArrayList<>();
for(int i=0;i<10;i++){
threads.add(new Thread(t::m,"thread-"+i));
}
threads.forEach((o)->o.start());
threads.forEach((o)->{
try {
o.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(t.count);
}
}
- 運行結果:
10000
出現ABA問題
– 加version,或者添加標籤解決問題
weakCompareAndSetObject