Java进阶(再论线程)——线程的4种创建方式 & 线程的生命周期 & 线程的3大特性 & 集合中的线程安全问题

    this.name = name;
}

@Override
public void run() {
    for(int i =0;i<10;i++){
        System.out.println("当前线程:"+this.name);
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

public static void main(String[] args) {
    new Thread(new ThreadB("B")).start();
}

}


### 3、实现Callable接口


![在这里插入图片描述](https://img-blog.csdnimg.cn/46d56dcb7f79431ca173a25f3cb81208.png)



package com.tianju.threadLearn;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
* Callable,可以有返回值
*/
public class ThreadC implements Callable {

@Override
public Long call() throws Exception {
    long sum = 0;
    for (int i = 0; i < 500000; i++) {
        sum+=i;
    }
    return sum;
}

public static void main(String[] args) throws ExecutionException, InterruptedException {
    FutureTask<Long> threadC = new FutureTask<Long>(new ThreadC());
    Thread thread = new Thread(threadC);
    thread.start();
    Long aLong = threadC.get();
    System.out.println(aLong);
}

}


![在这里插入图片描述](https://img-blog.csdnimg.cn/ffa6ba3e47a1450b83dd73b4f79ed2c4.png)


![在这里插入图片描述](https://img-blog.csdnimg.cn/b14ee1f4f71349d29e76ae63b569afdb.png)


![在这里插入图片描述](https://img-blog.csdnimg.cn/e6fcf67aac8443d5887fde2ef87d1fe5.png)


![在这里插入图片描述](https://img-blog.csdnimg.cn/a2459384ac00408a88f2e8654640f690.png)


### 4、线程池


池化技术pool【常量池、数据连接池、线程池】


![在这里插入图片描述](https://img-blog.csdnimg.cn/ad11ab5cb6514f85ad993c77493cc17d.png)



package com.tianju.threadLearn;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class PoolDemo1 {
public static void main(String[] args) {
System.out.println(“=缓存线程池==”);
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i=0;i<10;i++) {
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread());
}
});
}
System.out.println(“=固定线程池==”);
ExecutorService executorService2 = Executors.newFixedThreadPool(1);
for (int i=0;i<10;i++) {
executorService2.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread());
}
});
}
}
}


## 二、线程的生命周期


![在这里插入图片描述](https://img-blog.csdnimg.cn/d3527b26da9c49e28762a7caa379121f.png)


### join():运行结束再下一个


![在这里插入图片描述](https://img-blog.csdnimg.cn/2f94331774534cae8d7303ced38fd210.png)



package com.tianju.threadLearn;

public class ThreadA1 extends Thread{

static int c = 0;

@Override
public void run(){
    for (int i = 0; i < 20; i++) {

        try {
            System.out.println(this.getName()+": "+i);
            sleep(300);
            c++;
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

public static void main(String[] args) throws InterruptedException {
    ThreadA1 a = new ThreadA1();
    a.setName("A");

    ThreadA1 b = new ThreadA1();
    b.setName("B");
    a.start();
    a.join(); // A运行结束,B才能开始运行

    b.start();
    b.join(); // 控制执行顺序

    System.out.println(Thread.currentThread().getName());
    System.out.println("c的结果为: "+c);

}

}


![在这里插入图片描述](https://img-blog.csdnimg.cn/410cbc6e4abc4aa89c3572f88d0fb0b9.png)


### yield():暂时让出cpu的使用权


![在这里插入图片描述](https://img-blog.csdnimg.cn/ea6ec42649a640ecbb07c42c5a0aa8ec.png)



package com.tianju.threadLearn;

/**
* yield,让出cpu的使用权
*/
public class ThreadA2 extends Thread{

@Override
public void run(){
    for (int i = 0; i < 20; i++) {

        try {
            if (i%2==0){
                // 让出cpu的使用权,避免一个线程一直占有cpu,防止独占cpu
                // 重新竞争
                yield();
            }
            System.out.println(this.getName()+": "+i);
            sleep(300);

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

public static void main(String[] args) throws InterruptedException {
    ThreadA2 a = new ThreadA2();
    a.setName("A");

    ThreadA2 b = new ThreadA2();
    b.setName("B");
    a.start();

    b.start();

    System.out.println(Thread.currentThread().getName());

}

}


### deamon():守护线程,最后结束


![在这里插入图片描述](https://img-blog.csdnimg.cn/9257035e5fa449cc927c9fb7f5426e2a.png)


![在这里插入图片描述](https://img-blog.csdnimg.cn/ff9f55464812475f8be3bc467a4018b1.png)



package com.tianju.threadLearn;

/**
* 守护线程
* 用户线程
*
*/
public class ThreadA3 extends Thread{

@Override
public void run(){

    while (true){
        System.out.println("我是守护线程.......");
        try {
            sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

public static void main(String[] args) throws InterruptedException {

    ThreadA3 a = new ThreadA3();
    a.setName("A");
    a.setDaemon(true); // 守护线程,用户线程main结束后,他就结束了
    a.start();

    for (int i =0;i<10;i++){
        System.out.println(Thread.currentThread()+":"+i);
        Thread.sleep(200);
    }

}

}


![在这里插入图片描述](https://img-blog.csdnimg.cn/7cce831beccb4dafbdcab38ecab6031a.png)


### sleep():如果有锁,不会让出


![在这里插入图片描述](https://img-blog.csdnimg.cn/2ec4289cdb014fefaaf28dd65058b191.png)



package com.tianju.threadLearn;

public class ThreadSleep extends Thread{

@Override
public void run(){

    for (int i=0;i<10;i++){
        System.out.println("我是线程A:"+this.getName());

        try {
            sleep(200); // 不会让出锁
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

}

public static void main(String[] args) {
    ThreadSleep threadA = new ThreadSleep();
    threadA.setName("线程A");

    threadA.start(); // 我准备好了

    String name = Thread.currentThread().getName();
    System.out.println(name);

}

}


## 三、线程的三大特性


![在这里插入图片描述](https://img-blog.csdnimg.cn/00e8f4fecd004ae7bdb95177f242bf84.png)


### 原子性:AtomicInteger


![在这里插入图片描述](https://img-blog.csdnimg.cn/1504907fe71f46d98e2f77b3a758a9c3.png)


![在这里插入图片描述](https://img-blog.csdnimg.cn/6c3e464a6f1a45e6a0f9a21b56183886.png)


![在这里插入图片描述](https://img-blog.csdnimg.cn/62a097c2632a4c2895ab3c778ef8cbd1.png)


![在这里插入图片描述](https://img-blog.csdnimg.cn/244c47558a1f48ce9711fc6619f800ae.png)



package com.tianju.tx;

import java.util.concurrent.atomic.AtomicInteger;

/**
* 解决原子性:AtomicInteger
*/
public class AtomicDemo1 {
static AtomicInteger x= new AtomicInteger();
static class A extends Thread{
@Override
public void run() {

        for (int i = 0; i < 20; i++) {
            x.incrementAndGet();
            System.out.println(getName()+ "--x:"+x);
            try {
                sleep(200);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }
    }
}

public static void main(String[] args) {
    new A().start();
    new A().start();
    new A().start();
}

}


![在这里插入图片描述](https://img-blog.csdnimg.cn/0631ad9ef9724f4f91a837fc1806f1d9.png)


#### CAS



> 
> CAS(Compare And Swap)
> 
> 
> 


* 从主存拷贝到工作内存(线程)
* 修改,和主存比较,如果如果和取时结果一致,刷新到主存中。



> 
> ABA问题:
> 
> 
> 如果红色线程拿到了主存中的3,进行加1,;
> 
> 
> 蓝色线程也拿到了主存中的3,进行了加1,然后又减1;
> 
> 
> 红色线程一直问主存里面是不是3,然后发现还是3,就把4写到主存里面;
> 
> 
> 但是此时的3已经被蓝色线程动过了;
> 
> 
> 解决方案是,加一个版本号,每次被操作,就让版本号加1
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/8a296f85af6a4d4a8390fab350aba28b.png)


### 可见性:加volatile关键字


![在这里插入图片描述](https://img-blog.csdnimg.cn/e9a9fc4a755f4681bca9e9af165bbc80.png)



package com.tianju.view;

/**
* 线程之间不可见
* volatile 用于解决可见性
*/
public class VisibleDemo2 {
volatile static boolean f = true; // 处理可见性,解决不了原子性
static class A extends Thread{

    @Override
    public void run() {
        while (f){

        }
        System.out.println("A的f为:"+f);
    }
}
static class B extends Thread{
    @Override
    public void run() {
        f=false;
        System.out.println("B设置f为:"+f);
    }
}

public static void main(String[] args) throws InterruptedException {
    new A().start();
    Thread.sleep(300);
    new B().start();
}

}


![在这里插入图片描述](https://img-blog.csdnimg.cn/ccfba2bebd5d461190561a4cd8747f4e.png)


### 有序性:引用有了,对象还没


![在这里插入图片描述](https://img-blog.csdnimg.cn/742a4e1ea92544f1bf5f101db3d440d4.png)



> 
> 假设: 编译器修改顺序 1 , 3, 2
> 
> 
> 线程A执行到对象初始化阶段,还没有初始化;
> 
> 
> 线程B先获得的对象的引用,然后调用对象,
> 
> 
> 但是对象还没有初始化,因此会报错,对象初始化错误
> 
> 
> 


![在这里插入图片描述](https://img-blog.csdnimg.cn/b4b7c4571ec54f538842e8074ea5eb02.png)


## 四、集合中的线程安全问题


### 1、List集合的问题


![在这里插入图片描述](https://img-blog.csdnimg.cn/c138462c042f41d284c840f687c87ad1.png)


![在这里插入图片描述](https://img-blog.csdnimg.cn/514f303f0f29461a882406cfa4f064d2.png)



package com.tianju.collection;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class ListDemo {
static List list = new ArrayList<>();

// 有序性+原子性保证
volatile static AtomicInteger index =new AtomicInteger(0);
static class A extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            list.add(index.incrementAndGet());
        }
    }
}

public static void main(String[] args) throws InterruptedException {
    A a1 = new A();
    A a2 = new A();
    A a3 = new A();
    a1.start();
    Thread.sleep(500);
    a2.start();
    a3.start();
    System.out.println(list);
}

}


#### 用vector解决


![在这里插入图片描述](https://img-blog.csdnimg.cn/a6c1dfe726544d55a01cb34548069300.png)



package com.tianju.collection;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger;

public class VectorDemo {
static Vector list = new Vector<>();

// 有序性+原子性保证
volatile static AtomicInteger index =new AtomicInteger(0);
static class A extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            list.add(index.incrementAndGet());
        }
    }
}

public static void main(String[] args) throws InterruptedException {
    A a1 = new A();
    A a2 = new A();
    A a3 = new A();
    a1.start();
    a1.join(); // A运行结束,B才能开始运行
    a2.start();
    a2.join();
    a3.start();
    a3.join();
    System.out.println(list);
}

}


#### 用Collections.synchronizedList



package com.tianju.collection;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.atomic.AtomicInteger;

public class CollectionDemo {
static List ls = new ArrayList<>();
static List list = Collections.synchronizedList(ls);

// 有序性+原子性保证
volatile static AtomicInteger index =new AtomicInteger(0);
static class A extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            list.add(index.incrementAndGet());
        }
    }
}

public static void main(String[] args) throws InterruptedException {
    A a1 = new A();
    A a2 = new A();
    A a3 = new A();
    a1.start();
    a1.join(); // A运行结束,B才能开始运行
    a2.start();
    a2.join();
    a3.start();
    a3.join();
    System.out.println(list);
}

}


![在这里插入图片描述](https://img-blog.csdnimg.cn/2cc702151baa430aabac9e2d14825553.png)


### 2、表格总结




| 序号 | 线程不安全 | 线程安全 |
| --- | --- | --- |
| 1 | ArrayList | Vector/ Collections.synchronizedList(list) |
| 2 | HashMap | ConcurentHashMap/HashTable |
| 3 | HashSet | Collections.synchronizedSet() |


Hashset的底层是HashMap


![在这里插入图片描述](https://img-blog.csdnimg.cn/d9c5ebfd3c80427bb1588aa473a17a4a.png)


### 3、关于hash算法


比如一开始有蓝色点,经过hash算法之后,得到结果3,然后放到相应的位置;


然后又来了一个红色的点,经过hash算法之后,也是3,此时就顺着蓝色的位置去找;


之前是采用头插法,就是新来的放到蓝色的之前,在1.8之后改成尾插法,放到蓝色的后面;


如果又有新来的,就继续往后面加,此时出现了不利的情况,就是越来越多成了一个很长的链表;


所以就采用了树的结果,这样提高的查找的效率;在1.8中采用的红黑树;


![在这里插入图片描述](https://img-blog.csdnimg.cn/ece1f0457740487b9fbedc79fcf468a8.png)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值