首页 > 编程语言 > 详细

Java多线程详解(2)

时间:2021-02-19 23:36:42      阅读:33      评论:0      收藏:0      [点我收藏+]

多线程详解

1.线程同步机制

  ①并发—同一个对象被多个线程同时操作

  ②线程同步安全性形成条件:队列+锁

  ③为了保证数据在方法中被访问时的正确性,在访问时加入锁机制(synchronized)

  ④为了保证安全性,会导致性能降低

  ⑤一个优先级高的线程等待一个优先级低的线程释放锁,会引起优先级倒置,引起性能问题

 

2、同步方法及同步块

  ①同步方法

public synchronized void method(int args){}

  ②同步块—Obj同步监视器

       锁的对象是变化的量,需要增删改

synchronized(Obj){}

  ③synchronized方法控制对对象的访问,每个对象对应一把锁,每个synchronized方法必须都获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获得这个锁,继续执行

 

3、CopyOnWriteArrayList

  CopyOnWriteArrayList是JUC安全类型的集合

 1 public class TestJUC {
 2     //测试JUC安全类型的集合
 3     public static void main(String[] args) {
 4         CopyOnWriteArrayList<String> list=new CopyOnWriteArrayList<String>();
 5         for (int i = 0; i < 10000; i++) {
 6             new Thread(()->{
 7                 list.add(Thread.currentThread().getName());
 8             }).start();
 9         }
10 ?
11         try {
12             Thread.sleep(3000);
13         } catch (InterruptedException e) {
14             e.printStackTrace();
15         }
16 ?
17         System.out.println(list.size());
18     }
19 }

 

4、死锁

  ①死锁就是多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形

  ②产生死锁的必要条件

      1.互斥条件:一个资源每次只能被一个进程使用

      2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放

      3.不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺

      4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

      想办法破坏其中一个或多个条件便可以解开死锁

 1 public class TestLock {
 2     public static void main(String[] args) {
 3         MakeUp g1=new MakeUp(0,"A");
 4         MakeUp g2=new MakeUp(1,"B");
 5         g1.start();
 6         g2.start();
 7     }
 8 }
 9 ?
10 //口红
11 class Lipstick{
12 }
13 ?
14 //镜子
15 class Mirror{
16 }
17 ?
18 class MakeUp extends Thread{
19     //需要的资源只有一份,用static来保证只有一份
20     static Lipstick lipstick=new Lipstick();
21     static Mirror mirror=new Mirror();
22     int choice;//选择
23     String girlname;//使用化妆品的人
24 ?
25     MakeUp(int choice,String girlname){
26         this.choice=choice;
27         this.girlname=girlname;
28     }
29 ?
30     @Override
31     public void run() {
32         //化妆
33         try {
34             makeup();
35         } catch (InterruptedException e) {
36             e.printStackTrace();
37         }
38     }
39 ?
40     private void makeup() throws InterruptedException {
41         if(choice==0){
42             synchronized (lipstick){//获得口红的锁
43                 System.out.println(this.girlname+"获得口红的锁");
44                 Thread.sleep(1000);
45                 synchronized (mirror){//一秒钟后获得镜子的锁
46                     System.out.println(this.girlname+"获得了镜子的锁");
47                 }
48             }
49         }else{
50             synchronized (mirror){//获得镜子的锁
51                 System.out.println(this.girlname+"获得了镜子的锁");
52                 Thread.sleep(2000);
53                 synchronized (lipstick){//二秒钟后获得口红的锁
54                     System.out.println(this.girlname+"获得口红的锁");
55                 }
56             }
57         }
58     }
59 }

 

5、Lock(锁)

  ①从JDK5开始,Java提供了更强大的线程同步机制,通过显式定义同步锁对象来实现同步

  ②java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具,锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象

  ③ReentrantLock类(可重入锁)实现了Lock

 1 class c{
 2      private final ReentrantLock lock=new ReentrantLock();
 3     public void m(){
 4         lock.lock();
 5         try{
 6             //保证线程安全的代码
 7         }finally{
 8             lock.unlock();
 9             //如果同步代码有异常,要将unlock()写入finally语句块
10         }
11     }
12 }

 

6、线程协作

  生产者消费者问题是线程协作。仓库中不存在物品,则消费者要等待生产者生产,否则直接拿走物品;而生产者在仓库中不存在物品时,要生产物品并放入仓库,否则等待消费者取走物品。该问题需要线程同步和线程通信,所以只有synchronized不够。

  Java提供了几个方法解决线程之间的通信问题

 

方法名作用
wait() 表示线程一直等待,直到其他线程通知,与sleeep不同,会释放锁
wait(long timecut) 指定等待的毫秒数
notify() 唤醒一个处于等待状态的线程
notifyAll() 唤醒同一个对象上所有调用wait()方法的线程,优先级别高的线程优先调度

  实现方法

      管程法—生产者和消费者共用缓冲区

      信号灯法—通过一个标志位实现

 

7、线程池

  提前创建多个线程,并将其放入线程池中;使用时直接获取,使用完放回线程池,可以避免频繁地创建销毁,实现重复利用

  好处:提高响应速度、降低资源消耗、便于线程管理

      corePoolSize—核心池的大小

      maximumPoolSize—最大线程数

      keepAliveTime—线程没有任务时最多保持多长时间会终止

  线程池接口—ExecutorService

 1 public class TestPool {
 2     public static void main(String[] args) {
 3         //1.创建服务,创建线程池
 4         //newFixedThreadPool 参数为:线程池大小
 5         ExecutorService service= Executors.newFixedThreadPool(10);
 6         //执行
 7         service.execute(new MyThread());
 8         service.execute(new MyThread());
 9         service.execute(new MyThread());
10         //2.关闭连接
11         service.shutdown();
12     }
13 }
14 ?
15 class MyThread implements Runnable{
16     @Override
17     public void run() {
18         System.out.println(Thread.currentThread().getName());
19     }
20 }

 

 

Java多线程详解(2)

原文:https://www.cnblogs.com/yqsumAll/p/14418042.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!