java并发编程和高并发基础二

三 多线程基础类

共享数据:

  1. 如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据(共享一个继承了Runnable接口的对象)
    在这里插入图片描述
  2. 如果每个线程执行的代码不同,这时候需要用不同的Runnable对象,实现一个Runnable接口匿名内部类来新建线程来操作同一个对象实例。
    在这里插入图片描述

3.1 Thread

public class MyThread extends Thread {

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }

    }

}

    public static void main(String[] args) {
        Thread myThread = new MyThread();
        myThread.start();
    }

stop():过期方法,
interrupt():仅仅是在当前线程中打了一个停止的标记,并不是真正的停止线程。
isInterrrupt():测试线程是否已经中断。不清楚状态
interrupted():测试(当前线程)是否已经发生中断。线程的中断状态由该方法清除。如果连续两次调用该方法,则第二次将返回false。
可以参考《java多线程编程核心技术》1.7小节的例子

3.2 Runnable

public class MyRunnable implements Runnable{

    @Override
    public void run() {
        for(int i = 0;i < 5;i++){
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
    }
}

public static void main(String[] args) {
        //implements Runnable
        MyRunnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
    }

start()并不是立即执行多线程代码,使得该线程变成可运行状态,具体什么时候运行由系统决定。
注意:Thread和Runnable区别
一个类继承Thread,则不适合资源共享,但是如果实现了Runnable接口,可以实现资源共享。可以定义成员变量。

  1. sleep():
  2. yield():
  3. Thread.currentThread.getName(),getId()
  4. setDaemon(),isDaemon():用来设置线程是否成为守护线程和判断线程是否为守护线程。当进程中不存在非守护线程了,则守护线程自动销毁。典型的就是垃圾回收机制。

3.3 Callable

之前的Runnable和Thread在执行完成任务之后无法获取执行结果。
Furtask实现了Runnable和Future接口

public class MyCallable implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        int sum = 0;

        for (int i = 0; i <= 100000; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
            sum += i;
        }
        return sum;
    }
}
public class Test {
    public static void main(String[] args) {
        //implements Callable
        MyCallable myCallable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(myCallable);

        new Thread(futureTask).start();

        try {
            //FutureTask 类似于CountDownLatch的作用,最后执行
            Integer sum = futureTask.get();
            System.out.println("sum:"+sum);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

注意:可以获取结果,call()方法可以抛出异常

四 线程安全-同步容器

ArrayList->Vector,Stack 用synchronized的线程同步容器,操作差异会导致安全性,remove,add
HashMap->HashTable(key不能为空),hashtable是用synchronized
Collections.synchronizedXX(List,Set,Map),也是synchronized也是性能差
例子:
在这里插入图片描述

@Slf4j
@ThreadSafe
public class VectorExample1 {

    // 请求总数
    public static int clientTotal = 5000;

    // 同时并发执行的线程数
    public static int threadTotal = 200;

    private static List<Integer> list = new Vector<>();

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal; i++) {
            final int count = i;
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    update(count);
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("size:{}", list.size());
    }

    private static void update(int i) {
        list.add(i);
    }
}
@NotThreadSafe
public class VectorExample2 {

    private static Vector<Integer> vector = new Vector<>();

    public static void main(String[] args) {

        while (true) {

            for (int i = 0; i < 10; i++) {
                vector.add(i);
            }

            Thread thread1 = new Thread() {
                public void run() {
                    for (int i = 0; i < vector.size(); i++) {
                        vector.remove(i);
                    }
                }
            };

            Thread thread2 = new Thread() {
                public void run() {
                    for (int i = 0; i < vector.size(); i++) {
                        vector.get(i);
                    }
                }
            };
            thread1.start();
            thread2.start();
        }
    }
}
@Slf4j
@ThreadSafe
public class CollectionsExample1 {

    // 请求总数
    public static int clientTotal = 5000;

    // 同时并发执行的线程数
    public static int threadTotal = 200;

    private static List<Integer> list = Collections.synchronizedList(Lists.newArrayList());

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal; i++) {
            final int count = i;
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    update(count);
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("size:{}", list.size());
    }

    private static void update(int i) {
        list.add(i);
    }
}

五 同步容器-并发容器J.U.C

ArrayList->copyOnWriteArrayList(线程不安全)
jdk8如下:
在这里插入图片描述
get 没有加锁
add 加锁,复制数组,再指向新数组
读写分离
缺点:数据读取不实时 但最终一致性,适合读多写少。

HashSet、TreeSet->CopyOnWriteArraySet
ConcurrentSkipListSet(自然排序)
add,remove操作是线程安全的,addAll(),removeAll()不是线程安全的

HashMap,TreeMap->ConcurrentHashMap 高并发
ConcurrentSkipListMap key是有序的,和线程数无关

六 AQS

在这里插入图片描述

详见博客 https://blog.csdn.net/xi15232131135/article/details/104519436

安全共享对象策略 - 总结

  • 线程限制:一个被线程限制的对象,又线程独占,并且只能被占有它的现场修改
  • 共享只读:一个共享只读的对象,在没有额外同步的情况下,可以被多个线程并发访问,但是任何线程都不能修改它。
  • 线程安全对象:一个线程安全的对象或容器,在内部通过同步机制来保证线程安全,所以其他线程无需额外的同步就可以通过公共接口随意访问它。
  • 被守护对象:被守护对象只能通过获取特定的锁来访问。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值