java多线程

创建线程的三种方式

继承Thread类,重写run方法。

public class MyThread extends Thread{
    @Override
    public void run(){
        for (int i = 0; i < 10; i++) {
            System.out.println("子线程"+i);
        }
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
        for (int i=0; i<10;i++){
            System.out.println("主线程"+i);
        }
    }
}

获取和修改线程的名称

获取线程ID和线程名称

1.在Thread的子类中调用this.getId()或this.getName()
2.使用Thread.currentThread().getId()和Thread.currentThread.getName()
####修改线程名称
1.调用线程对象的setName()方法

public class MyThread extends Thread{
    @Override
    public void run(){
        for (int i = 0; i < 10; i++) {
            System.out.println("线程id"+this.getId()+" 线程名称"+this.getName()+"子线程"+i);
//        this.getId()获取线程id
//        this.getName()获取线程名称
//        Thread.currentThread()获取当前线程,等价于this
        }
    }

    public static void main(String[] args) {
        MyThread myThread1 = new MyThread();
        myThread1.start();
        MyThread myThread2 = new MyThread();
        myThread2.start();
        for (int i=0; i<10;i++){
            System.out.println("主线程"+i);
        }
    }
}

2.使用线程子类的构造方法赋值

实现runnable接口

public class MyRunable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i <= 10; i++) {
            System.out.println("MyRunnable"+i);
        }
    }
    public static void main(String[] args) {
        MyRunable mr = new MyRunable();
        Thread thread = new Thread(mr);
        thread.start();
    }
}

也可以用匿名内部类创建对象

public class MyRunnable {
    public static void main(String[] args) {
//    创建可运行对象
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + "......." + i);
                }
            }
        };
//    创建线程对象
        Thread thread = new Thread(runnable, "我的线程");
//    启动线程    
        thread.start();
    }
}

//runnable卖票案列
public class Ticket implements Runnable{
    private int ticket = 100;

    @Override
    public void run() {
        for(int i =0;i<ticket;i++){
            System.out.println(Thread.currentThread().getName()+" 卖了第"+i+"票");
        }
    }

    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        Thread thread1 = new Thread(ticket,"窗口1");
        Thread thread2 = new Thread(ticket,"窗口2");
        Thread thread3 = new Thread(ticket,"窗口3");
        Thread thread4 = new Thread(ticket,"窗口4");
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }
}

线程的状态

new 初始状态: 线程对象被创建,只在堆中开辟内存,与常规对象无异。
ready就绪状态:调用start之后,进入就绪状态,等待被选中并分配时间片。
running运行状态:获得时间片之后,进入运行状态,如果时间片到期,则回到就绪状态。
Terminated终止状态:主线程main()或独立线程run()介绍,并进入终止状态,并释放持有的时间片。

线程休眠

public class SleepThread extends Thread {
    public void run(){
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"-----"+i);
            try {
//                线程休眠1000毫秒
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
class Test{
    public static void main(String[] args) {
        SleepThread sleepThread = new SleepThread();
        sleepThread.start();
    }
}

线程放弃

public class YieldThread extends Thread {
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "-----" + i);
//            主动放弃cpu
            Thread.yield();
        }
    }
}
class Test{
    public static void main(String[] args) {
        YieldThread yieldThread1 = new YieldThread();
        yieldThread1.start();
        YieldThread yieldThread2 = new YieldThread();
        yieldThread2.start();
    }
}

加入线程

public class JoinThread extends Thread {
    @Override
    public void run(){
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"----"+i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Test{
    public static void main(String[] args) {
        JoinThread joinThread1 = new JoinThread();
        joinThread1.start();
        try {
//            加入当前线程,并阻塞当前线程,直到加入线程执行完毕,且join线程必须加入在start之后
            joinThread1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 20; i++) {
            System.out.println(Thread.currentThread().getName()+"===="+i);
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

线程常见方法

优先级

线程对象.setPriority()
线程的优先级为1-10级,默认为5级,优先级越高,表示获得cpu的机会越多。

守护线程

线程对象.setDaaemon(true):设置为守护线程,需要设置在start方法之前。
线程有两类:用户线程(前台线程)、守护线程(后台线程)
如果程序中所有的前台线程都执行完毕了,后台线程会自动结束。
垃圾回收器中的线程是属于守护线程。

多线程安全问题

当多线程并发访问临界资源时,如果破坏原子操作,可能会造成数据不一致。
临界资源:共享资源(同一对象),一次仅允许一个线程使用,才能保证其正确性
原子操作:不可分割的多步操作,被视作一个整体,其顺序和步骤不可被打乱或者缺省。

解决方法

(1)同步代码块
synchronized(临界资源对象){ //在run方法中对临界资源对象加锁
// 代码(原子操作)

注:
每个对象都有一个互斥锁标记,用来分配给线程的
只有拥有对象互斥锁标记的线程,才能进入该对象加锁的同步代码块。
线程退出同步代码块的时候,会释放相对应的互斥锁标记。

import java.util.Arrays;

public class ThreadSafe {
    private static int index = 0;
    public static void main(String[] args) {
        String [] string = new String[5];
        Runnable runnableA = new Runnable() {
            @Override
            public void run() {
//                同步代码块
                synchronized (string) {
                    string[index] = "hello";
                    index++;
                }
            }
        };
        Runnable runnableB = new Runnable() {
            @Override
            public void run() {
//                同步代码块
                synchronized (string) {
                    string[index] = "world";
                    index++;
                }
            }
        };

        Thread a = new Thread(runnableA,"A");
        Thread b = new Thread(runnableB,"B");
        a.start();
        b.start();

        try {
            a.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        try {
            b.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Arrays.toString(string));
    }
}

//卖票案例
import java.awt.*;

public class Ticket implements Runnable {
    private int ticket = 100;
    //    创建锁
    private Object object = new Object();

    @Override
    public void run() {
//      也可以不创建锁 以当前对象为锁,即this替换object
            while (true){
              synchronized (object) {
                if (ticket <= 0) {
                    break;
                }
                System.out.println(Thread.currentThread().getName() + "售出第" + ticket + "张票");
                ticket--;

            }
        }
    }
}


class Test {
    public static void main(String[] args) {

        Ticket ticket = new Ticket();

        Thread thread1 = new Thread(ticket, "售票口1");
        Thread thread2 = new Thread(ticket, "售票口2");
        Thread thread3 = new Thread(ticket, "售票口3");
        Thread thread4 = new Thread(ticket, "售票口4");

        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }
}

//存取款案例
public class TestBankCard {
    public static void main(String[] args) {
        BankCard card = new BankCard();
        Runnable add = new Runnable() {
            @Override
            public void run() {

                for (int i = 0; i < 10; i++) {
                    synchronized (card) {
                        card.setMoney(card.getMoney() + 1000);
                        System.out.println(Thread.currentThread().getName() + "存了1000" + "余额是" + card.getMoney());
                    }
                }
            }
        };
        Runnable sub = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    synchronized (card) {
                        if (card.getMoney() >= 1000) {
                            card.setMoney(card.getMoney() - 1000);
                            System.out.println(Thread.currentThread().getName() + "取了1000" + "余额是" + card.getMoney());

                        } else {
                            System.out.println("余额不足");
                            i--;

                        }
                    }
                }
            }
        };
        Thread addMoney = new Thread(add, "小李");
        Thread subMoney = new Thread(sub, "校长");
        addMoney.start();
        subMoney.start();
    }
}

线程通信

等待:

	public final void wait()
	public final void wait(long timeout)

必须在对obj加锁对同步代码块中。在一个线程中,调用obj.wait()时,次线程会释放其拥有的所有锁标记。同时此线程阻塞在o的等待队列中,释放锁,进入等待队列。

通知:

public class BankCard {
    private double money;

    private boolean flag;

    public synchronized void save(double m) {
        if (flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        money = m + money;
        System.out.println(Thread.currentThread().getName() + "存了1000元,余额为" + money);
        flag = true;
        this.notify();
    }

    public synchronized void take(double m) {
        if (!flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        money = money-m;
        flag = false;
        System.out.println(Thread.currentThread().getName() + "取了1000元,余额为" + money);
        this.notify();
    }

}
public class SubMoney implements Runnable {
    private BankCard card;

    public SubMoney(BankCard card) {
        this.card = card;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            card.take(1000);
        }
    }
}
public class AddMoney implements Runnable{
    private BankCard card;

    public AddMoney(BankCard card) {
        this.card = card;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10 ; i++) {
            card.save(1000);
        }
    }
}
public class Test {
    public static void main(String[] args) {
        BankCard card = new BankCard();
        AddMoney addMoney = new AddMoney(card);
        SubMoney subMoney = new SubMoney(card);

        Thread t1 = new Thread(addMoney,"m");
        Thread t2 = new Thread(subMoney,"n");

        t1.start();
        t2.start();
    }
}

生产者与消费者案列

package Bread01;

public class Bread {
    private int id;
    private String productName;

    public Bread() {
        super();
    }

    public Bread(int id, String productName) {
        this.id = id;
        this.productName = productName;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;


    }
}
package Bread01;

public class BreadCon {
    private Bread[] con = new Bread[30];
    private int index = 0;

    public synchronized void input(Bread b) {
        while (index >= 6) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        con[index] = b;
        index++;
        System.out.println(Thread.currentThread().getName() + "制作了 " + b.getId());
        this.notifyAll();
    }

    public synchronized void output() {
        while (index <= 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        index--;
        Bread b = con[index];
        System.out.println(Thread.currentThread().getName() + "取走了 " + b.getId());
        con[index] = null;
        this.notifyAll();
    }
}
package Bread01;

public class Consume implements Runnable {
    BreadCon con;

    public Consume(BreadCon con) {
        super();
        this.con = con;

    }

    @Override
    public void run() {
        for (int i = 0; i < 30; i++) {
            con.output();
        }
    }
}
package Bread01;

public class Product implements Runnable {
    BreadCon con ;

    public Product(BreadCon con) {
        super();
        this.con = con;
    }

    @Override
    public void run() {
        for (int i = 0; i < 30; i++) {
            con.input(new Bread(i,Thread.currentThread().getName()));
        }
    }
}
package Bread01;

public class Test {
    public static void main(String[] args) {
        BreadCon con = new BreadCon();
        Product product = new Product(con);
        Consume consume = new Consume(con);

        Thread t1 = new Thread(product,"a");
        Thread t2 = new Thread(consume,"b");
        Thread t3 = new Thread(product,"c");
        Thread t4 = new Thread(consume,"d");

        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

线程池

1.线程容器,可设定线程分配的数量上限
2。将预先创定的线程对象存入池中,并重用线程池中的线程对象
3。避免频繁的创建和销毁线程

线程池原理

将任务交给线程池,由线程池奉陪线程,运行任务,并在任务结束复用线程。

创建线程池

Executor:线程池顶级接口。
ExecutorService:线程池接口,可通过submit(Runnable task)提交任务代码。
Executors工厂类:通过此类可以获得一个线程类。
通过newFixedThreadPool(int nThreads)获取固定数量的线程池。参数:指定线程池中线程的数量。
通过newCachedThreadPool()获得动态数量的线程池,如不够则创建新的,没有上限。

package Demo01;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class demo1 {
    public static void main(String[] args) {
//        1.创建固定线程池个数
        ExecutorService es = Executors.newFixedThreadPool(4);
//        2.创建任务
        Runnable runnable = new Runnable() {
            private int ticket = 100;
            @Override
            public void run() {
                while (true){
                    if (ticket<=0){
                        break;
                    }
                    System.out.println(Thread.currentThread().getName() + "买了第"+ticket+"张票");
                    ticket--;
                }
            }
        };
//        3.提交任务
        for (int i = 0; i < 4; i++) {
            es.submit(runnable);
        }
//        4.关闭线程
        es.shutdown();
    }
}

Callable接口

与runnable接口类似,实现之后代表一个线程任务,Callable具有泛型返回值、可以声明异常。

package Demo01;

import java.util.concurrent.*;

public class demo1 {
    public static void main(String[] args) {
//        1.创建线程池
        ExecutorService es = Executors.newFixedThreadPool(1);
//        2.提交任务Future,表示将要执行任务的结果
        Future<Integer> future = es.submit(new Callable<Integer>() {

            @Override
            public Integer call() throws Exception {
                System.out.println(Thread.currentThread().getName()+"开始计算");
                int sum = 0;
                for (int i = 0; i <= 100; i++) {
                    sum +=i;
                }
                return sum;
            }
        });
//        3.获取结果
        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
//        4.关闭线程池
        es.shutdown();
    }
}

Future接口

Future表示将要完成任务的结果。
表示ExecutorService.submit()所返回的状态结果,就是call的返回值
get()以阻塞的形式等待Future中的异步处理结果(call()的返回值)
同步:形容一次方法调用,同步一旦开始,调用者必须等待该方法返回,才能继续。
异步:形容一次方法调用,异步一旦开始,像是一次消息传播,调用者告知之后立刻返回,两者竞争时间片,并发执行。
有等待就是同步,不等待就是异步,异步有多条执行路径,同步只有一条执行路径。
多次调用Future接口

package Demo01;

import java.util.concurrent.*;

public class demo1 {
    public static void main(String[] args) throws Exception{
        ExecutorService es = Executors.newFixedThreadPool(2 );
        Future<Integer> future1 = es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 0; i <= 50; i++) {
                    sum+=i;
                }
                return sum;
            }
        });
        Future <Integer> future2 = es.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 50; i <= 100; i++) {
                    sum+=i;
                }
                return sum;
            }
        });
        int sum = future1.get()+ future2.get();
        System.out.println("结果是"+sum);
        es.shutdown();

    }
}

Lock接口的使用

与synchronized比较,显示定义,结构更加灵活。
常用方法
void lock() //获取锁
boolean tryLock()//尝试获取锁,(成功返回true,失败返回false,不阻塞)
void unlock() //释放锁

重入锁
ReentrantLock:lock的实现类,与synchronized一样具有互斥锁的功能

package Demo01;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyList {
    private Lock lock = new ReentrantLock();
    private String[]str = {"A","B","","",""};
    private int count = 2;

    void add(String value){
        lock.lock();
        try {
            str[count]=value;
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            count++;
            System.out.println(Thread.currentThread().getName() + "添加了"+value);
        }finally {
            lock.unlock();
        }
    }

    public String[] getStr() {
        return str;
    }
}
package Demo01;

import java.util.Arrays;

public class Test {
    public static void main(String[] args) throws Exception{
        MyList list = new MyList();
        Runnable runnable1 = new Runnable() {
            @Override
            public void run() {
                list.add("hello");
            }
        };
        Runnable runnable2 = new Runnable() {
            @Override
            public void run() {
                list.add("world");
            }
        };

        Thread t1 = new Thread(runnable1);
        Thread t2 = new Thread(runnable2);
        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Arrays.toString(list.getStr()));
    }
}

读写锁

ReentrantReadWriteLock:
一次支持一写多读的同步锁,读写分离,可分别 分配读锁,写锁。
支持多次分配读锁,是多个读操作可以并发执行。
互斥规则
写写 :互斥,阻塞。
读写 :互斥,读阻塞写,写阻塞读。
读读 :不互斥,不阻塞。
在读写操作远远高于写操作的环境中,可在保障线程安全的情况下,提高运行效率。

package Demo01;

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteDemo {
    //    创建读写锁
    private ReentrantReadWriteLock rll = new ReentrantReadWriteLock();
    //    获取读锁
    private ReentrantReadWriteLock.ReadLock readLock = rll.readLock();
    //    获取写锁
    private ReentrantReadWriteLock.WriteLock writeLock = rll.writeLock();
    private String value;

    public String getValue() {
//        使用读锁上锁
        readLock.lock();
        try {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } finally {
            readLock.unlock();
        }
        System.out.println("读取操作"+value);
        return this.value;
    }

    public void setValue(String value) {
        writeLock.lock();
        try {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } finally {
            writeLock.unlock();
        }
        System.out.println("写入操作"+value);
        this.value = value;
    }
}
package Demo01;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {
    public static void main(String[] args) {
        ReadWriteDemo readWriteDemo = new ReadWriteDemo();
//    创建线程池
        ExecutorService es = Executors.newFixedThreadPool(20);
        Runnable read = new Runnable() {
            @Override
            public void run() {
                readWriteDemo.getValue();
            }
        };
        Runnable write = new Runnable() {
            @Override
            public void run() {
                readWriteDemo.setValue("张三"+new Random().nextInt(100));
            }
        };
        long start = System.currentTimeMillis();
        //    分配两个写的任务
        for (int i = 0; i < 2; i++) {
            es.submit(write);
        }
//    分配18读取任务
        for (int i = 0; i < 18; i++) {
            es.submit(read);
        }

        es.shutdown();
        while (es.isTerminated()){

        }
        long end = System.currentTimeMillis();
        System.out.println("用时间"+(end - start));
    }
}

CopyOnWriteArrayList

线程安全的ArrayList,加强版的读写分离
写有锁,读无锁,读写之间不阻塞,优于读写锁
写入时,先copy一个容器副本,再添加新元素,最后替换引用。
使用方式和ArrayList无异。

package Demo01;

import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo {
    public static void main(String[] args) {
//        1.创建集合
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
//        2.使用多线程操作
        ExecutorService es = Executors.newFixedThreadPool(5);
//        3.提交任务
        for (int i = 0; i < 5; i++) {
            es.submit(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 10; j++) {
                        list.add(Thread.currentThread().getName()+"...."+new Random().nextInt(1000));
                    }
                }
            });
        }
        es.shutdown();
        while (!es.isTerminated()){

        }
        System.out.println("元素个数"+list.size());
        for (String string:list){
            System.out.println(string);
        }
    }
}

CopyOnWriteArraySet

线程安全的Set,底层使用CopyOnWriteArrayList 实现
唯一不同在于,使用addIfAbsent()添加元素,会遍历数组。
如存在元素,则不添加(扔掉副本)。

Queue接口(队列)

Collection的子接口,表示FIFO(First In First Out)先进先出

package Demo01;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo {
    public static void main(String[] args) {
//        1.创建队列
        Queue<String> queue = new LinkedList<>();
//        2.入队
        queue.add("苹果");
        queue.add("橘子");
        queue.add("西瓜");
        queue.add("榴莲");
//        3.出队
        int size = queue.size();
        for (int i = 0; i < size; i++) {
            System.out.println(queue.poll());
        }
    }
}

ConcurrentLinkedQueue

线程安全、可高效对鞋的队列,高并发下性能最好的队列。
无锁,CAS比较交换算反,修改的方法包含三个核心参数(V,E,N)
V:要更新的变量 E预期值 N新值
只有当V==E时,V=N,否则表示已被更新过,取消当前操作。

package Demo01;

import java.util.concurrent.ConcurrentLinkedQueue;

public class Demo01 {
    public static void main(String[] args) throws Exception{
//        1.创建安全队列
        ConcurrentLinkedQueue<Integer> queue = new ConcurrentLinkedQueue<>();
//        2.入队操作
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    queue.offer(i);
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    queue.offer(i);
                }
            }
        });
//        3.启动线程
        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println("--------出队----------");
        int size = queue.size();
        for (int i = 0; i < size; i++) {
            System.out.println(queue.poll());
        }
    }
}

BlockingQueue接口(阻塞队列)

Queue的子接口,阻塞的队列,增加了两个线程状态为无限期等待的方法。
生产者消费者案列

package Demo01;

import java.util.concurrent.ArrayBlockingQueue;

public class Demo03 {
    public static void main(String[] args) {
//        1.创建队列
        ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(6);
//        2.创建两个线程
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 30; i++) {
                    try {
                        queue.put(i);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "生产了第"+i+"号面包");
                }
            }
        },"晨晨");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 30; i++) {
                    try {
                        Integer number = queue.take();
                        System.out.println(Thread.currentThread().getName() + "消费了第"+number+"号面包");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }
        },"彬彬");
    t1.start();
    t2.start();
    }
}

ConcurrentHashMap

初始容量默认为16段,使用分锁设计
不对整个Map加锁。而是为每个段加锁,效率大大提高。
当多个对象存入同一个段时,才需要互斥。
最理想的状态为16个对象分别存入16个段,并行数量16
使用方式与HashMap无异。

package Demo01;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;

public class Demo03 {
    public static void main(String[] args) {
//        1.创建集合
        ConcurrentHashMap<String, String> hashMap = new ConcurrentHashMap<String, String>();
//        2.使用多线程添加数据
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 10; j++) {
                        hashMap.put(Thread.currentThread().getName()+"--"+j,j+"");
                        System.out.println(hashMap);
                    }
                }
            }).start();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值