Java线程并发

一、并发--线程同步synchronized

    在一个多线程的情况下,保证数据的安全性和准确性,同时还要提高性能

    线程不安全指的是:有负数或相同的数

    并发的条件:存在共享资源、多人、同时操作

    线程同步的实现机制:等待池队列+锁机制。

    java锁机制:synchronized

synchronized存在以下问题:

        1、一个线程持有锁会导致其他其他所有需要此锁的线程挂起

        2、在多线程竞争下,加锁、释放锁会导致比较多的上下文切换和调度延时,引起性能问题

        3、如果优先级高的线程等待一个优先级低的线程释放锁,会导致优先级倒置,引起性能问题

synchronized使用方式:

synchronized方法:

        在操作共享资源的方法上面加synchronized关键字。(注意,syn锁的是当前对象的资源。也就是调用该方法的对象内部的属性。this的属性。如果方法内存在其他对象的属性,即:this.其他对象.属性,无法锁住)

synchronized同步块:

    synchronized(obj){},obj称为同步监视器

    在代码执行的的某一部分加syn块,同时监视相应的对象。

同步监视器执行过程:

    第一个线程访问,锁定同步监视器,执行代码

    第二个线程访问,发现同步监视器被锁定,无法访问

    第一个线程执行完毕,解锁同步监视器

    第二个线程访问,未发现同步锁,锁定并访问

具体用法:

package com.zzu.threadmethod;
import java.util.ArrayList;
import java.util.List;
public class SynBlockTest {
       public static void main(String[] args) {
              List<String> list = new ArrayList<String>();
              for (int i = 0; i <1000; i++) {
                     new Thread(()->{
                           synchronized (list) {//syn块
                                  list.add(Thread.currentThread().getName());
                           }
                     }).start();
              }
              try {
                     Thread.sleep(1000);
              } catch (InterruptedException e) {
                     e.printStackTrace();
              }
              System.out.println(list.size());
       }
}

举个线程例子:电影票

package com.zzu.threadmethod;
import java.util.ArrayList;
import java.util.List;
public class CinemaTest{
       public static void main(String[] args) {
              List<Integer> seates = new ArrayList<Integer>();
              seates.add(1);
              seates.add(2);
              seates.add(3);
              seates.add(4);
              seates.add(5);
              seates.add(6);
              Cinema cinema = new Cinema(seates, "lcx");
              List<Integer> seate = new ArrayList<Integer>();
              seate.add(1);
              seate.add(3);
              seate.add(5);
              List<Integer> seat = new ArrayList<Integer>();
              seat.add(1);
              seat.add(3);
              new Thread(new customer(cinema,seate),"李晨曦").start();
              new Thread(new customer(cinema,seat),"略略略").start();
       }
}
class Cinema{
       List<Integer> seates;
       String cinemaName;
       public Cinema(List<Integer> seates, String cinemaName) {
              this.seates = seates;
              this.cinemaName = cinemaName;
       }
       public boolean buyTickets(List<Integer> seat) {
              List<Integer> sea = new ArrayList<Integer>();
              synchronized (this) {//线程锁
                     sea.addAll(seates);
                     System.out.println("当前座位有:"+seates.toString());
                     sea.removeAll(seat);
                     if(sea.size()!=seates.size()-seat.size()) {
                           return false;
                     }
                     Thread.yield();//为了更好地看到效果
                     seates = sea;
              }
              return true;
       }
}
class customer implements Runnable{
       Cinema cinema;
       List<Integer> cusSeats;
       public customer(Cinema cinema, List<Integer> cusSeats) {
              this.cinema = cinema;
              this.cusSeats = cusSeats;
       }
       @Override
       public void run() {
              //synchronized (cinema) {在这里加锁也可以不过粒度比较大
                     boolean flag = cinema.buyTickets(cusSeats);
                     if(flag) {
                           System.out.println("购票成功!!!\n"+Thread.currentThread().getName()+"----->购买座位:"+cusSeats.toString());
                     }else {
                           System.out.println(Thread.currentThread().getName()+"购票失败,座位不够!!");
                     }
              //}
       }
}

二、并发容器

    java.util.concurrent.CopyOnWriteList 加有synchronized的容器。里面的锁是ReentrantLock可重复锁

三、并发--线程死锁

    双方互相占有地方需要的资源。解决方式:不要在同一代码块中持有两个锁

四、并发--线程协作

先了解一下wait()、notify()和notifyAll()方法:

wait方法:

1.wait()是Object里面的方法,而不是Thread里面的,这一点很容易搞错。它的作用是将当前线程置于预执行队列,并在wait()所在的代码处停止,等待唤醒通知。

2.wait()只能在同步代码块或者同步方法中执行,如果调用wait()方法,而没有持有适当的锁,就会抛出异常。

wait()方法调用后会释放出锁,线程与其他线程竞争重新获取锁。

方法示例:

public class TestWait implements Runnable {
    private final Object object=new Object();
    @Override
    public void run() {
        synchronized (object){
        System.out.println("线程执行开始。。。");
            try {
                object.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程执行结束。。。");
        }
    }
    public static void main(String[] args) {
        TestWait testWait=new TestWait();
        Thread thread=new Thread(testWait);
        thread.start();
    }
}

执行结果:

notify方法:

1.notify()方法也是要在同步代码块或者同步方法中调用的,它的作用是使停止的线程继续执行,调用notify()方法后,会通知那些等待当前线程对象锁的线程,并使它们重新获取该线程的对象锁,如果等待线程比较多的时候,则有线程规划器随机挑选出一个呈wait状态的线程。

2.notify()调用之后不会立即释放锁,而是当执行notify()的线程执行完成,即退出同步代码块或同步方法时,才会释放对象锁。

方法示例:

package com.zzu.threadmethod.cooperation;
public class TestWait implements Runnable{
       
       T obj ;//共享资源
       public boolean flag=true;//标志位
       
       TestWait(T obj){
              this.obj = obj;
       }
       
       public static void main(String[] args) {
              T obj = new T();//创建共享资源
              obj.a=0;
              obj.name="主线程";
              new Thread(new TestWait(obj),"lcx").start();//启动第一个线程,扔入共享资源
              new Thread(new TestWait(obj),"lhp").start();//启动第二个线程,扔入共享资源
              TestWait tt = new TestWait(obj);
              tt.flag=false;
              new Thread(tt,"lyb").start();//启动唤醒线程
       }
       @Override
       public void run() {
              try {//为了模拟多个线程竞争的延时
                     Thread.sleep(1000);
              } catch (InterruptedException e) {
                     e.printStackTrace();
              }
              //线程操作
              if(flag) {//根据标志位确定执行那种操作
                     synchronized (obj) {
                           System.out.println(Thread.currentThread().getName()+"---线程开始执行");
                           System.out.println("共享资源现状:"+obj.toString());
                           try {
                                  obj.wait();
                                  obj.a=3;
                                  obj.name=Thread.currentThread().getName();
                           } catch (InterruptedException e) {
                                  e.printStackTrace();
                           }
                           System.out.println(Thread.currentThread().getName()+"----线程结束执行");
                           System.out.println("共享资源现状:"+obj.toString());
                     }
              }else {
                     synchronized (obj) {
                           obj.notify();
                           obj.a=2;
                           obj.name="唤醒线程";
                           System.out.println(Thread.currentThread().getName()+"唤醒其他线程");
                           System.out.println("共享资源现状:"+obj.toString());
                     }
              }
       }
}
class T{
       int a;
       String name;
       @Override
       public String toString() {
              return "T [a=" + a + ", name=" + name + "]";
       }
}

执行结果如下:

notifyAll方法:

唤醒由当前资源调用wait方法阻塞的所有线程。不同类的线程都会唤醒

例子:    

package com.zzu.threadmethod.cooperation;
public class TestWait implements Runnable{
       
       T obj ;//共享资源
       public boolean flag=true;//标志位
       
       TestWait(T obj){
              this.obj = obj;
       }
       
       public static void main(String[] args) {
              T obj = new T();//创建共享资源
              obj.a=0;
              obj.name="主线程";
              new Thread(new TestWait(obj),"lcx").start();//启动第一个线程,扔入共享资源
              new Thread(new TestWait(obj),"lhp").start();//启动第二个线程,扔入共享资源
              new Thread(new TestWait(obj),"lz").start();//启动第二个线程,扔入共享资源
              new Thread(new TT(obj),"李晨曦").start();//启动第二个线程,扔入共享资源
              new Thread(new TestWait(obj),"lzh").start();//启动第二个线程,扔入共享资源
              TestWait tt = new TestWait(obj);
              tt.flag=false;
              new Thread(tt,"lyb").start();//启动唤醒线程
       }
       @Override
       public void run() {
              try {//为了模拟多个线程竞争的延时
                     Thread.sleep(1000);
              } catch (InterruptedException e) {
                     e.printStackTrace();
              }
              //线程操作
              if(flag) {//根据标志位确定执行那种操作
                     synchronized (obj) {
                           System.out.println(Thread.currentThread().getName()+"---线程开始执行");
                           System.out.println("共享资源现状:"+obj.toString());
                           try {
                                  obj.wait();
                                  obj.a=3;
                                  obj.name=Thread.currentThread().getName();
                           } catch (InterruptedException e) {
                                  e.printStackTrace();
                           }
                           System.out.println(Thread.currentThread().getName()+"----线程结束执行");
                           System.out.println("共享资源现状:"+obj.toString());
                     }
              }else {
                     try {//为了模拟多个线程竞争的延时
                           Thread.sleep(2000);
                     } catch (InterruptedException e) {
                           e.printStackTrace();
                     }
                     synchronized (obj) {
                           obj.notifyAll();
                           obj.a=2;
                           obj.name="唤醒线程";
                           System.out.println(Thread.currentThread().getName()+"唤醒其他线程");
                           System.out.println("共享资源现状:"+obj.toString());
                     }
              }
       }
}
class T{
       int a;
       String name;
       @Override
       public String toString() {
              return "T [a=" + a + ", name=" + name + "]";
       }
}
class TT implements Runnable{//另一个线程类
       
       T obj ;//共享资源
       
       TT(T obj){
              this.obj = obj;
       }
       
       @Override
       public void run() {
              //线程操作
              synchronized (obj) {
                     System.out.println(Thread.currentThread().getName()+"---线程开始执行");
                     System.out.println("共享资源现状:"+obj.toString());
                     try {
                           obj.wait();
                           obj.a=3;
                           obj.name=Thread.currentThread().getName();
                     } catch (InterruptedException e) {
                           e.printStackTrace();
                     }
                     System.out.println(Thread.currentThread().getName()+"----线程结束执行");
                     System.out.println("共享资源现状:"+obj.toString());
              }
       }
}

    生产者-消费者模式实现方案:共享内存或者信号灯法

1、管程法:

public class TestPC {
       public static void main(String[] args) {
              Queue<Goods> queue = new ArrayBlockingQueue<>(5);//共享资源
              Producer producer = new Producer(queue);
              Consumer consumer = new Consumer(queue);
              for (int i = 1; i < 5; i++) {
                     Thread threadA = new Thread(producer, "生产者" + i);//创建多个生产者
                     threadA.start();
              }
              for (int j = 1; j <= 5; j++) {
                     Thread threadB = new Thread(consumer, "消费者" + j);//创建多个消费者
                     threadB.start();
              }
       }
}
class Goods {//产品
       String name;
       public Goods(String name) {
              this.name = name;
       }
}
class Consumer implements Runnable {
       
       Queue<Goods> queue;
       
       public Consumer(Queue<Goods> queue) {
              this.queue = queue;
       }
       @Override
       public void run() {
              while (true) {
                     try {
                           Thread.sleep(500);
                     } catch (InterruptedException e1) {
                           e1.printStackTrace();
                     }
                     synchronized (queue) {
                           if (!queue.isEmpty()) {//有商品可以消费
                                  queue.poll();
                                  System.out.println(Thread.currentThread().getName() + "消费商品---剩余商品:" +  queue.size());
                                  if(queue.size()<5) {//释放生产者
                                         queue.notifyAll();
                                  }
                           } else {//没有商品,消费者等待
                                  try {
                                         System.out.println("消费者--"+Thread.currentThread().getName()+"--阻塞");
                                         queue.wait();
                                  } catch (InterruptedException e) {
                                         e.printStackTrace();
                                  }
                                  System.out.println("消费者--"+Thread.currentThread().getName()+"--被唤醒");
                           }
                     }
              }
       }
}
class Producer implements Runnable {
       
       private Goods goods;
       Queue<Goods> queue;
       
       public Producer(Queue<Goods> queue) {
              this.queue = queue;
       }
       @Override
       public void run() {
              while (true) {
                     try {
                           Thread.sleep(500);
                     } catch (InterruptedException e1) {
                           e1.printStackTrace();
                     }
                     synchronized (queue) {
                           goods = new Goods( "商品");
                           if (queue.size() <5) {//生产商品
                                  queue.add(goods);
                                  System.out.println(Thread.currentThread().getName() + "生产商品---剩余商品:" +  queue.size());
                                  if(queue.size()>0) {//释放消费者
                                         queue.notifyAll();
                                  }
                           } else {//共享资源已满,阻塞生产者
                                  try {
                                         System.out.println("生产者--"+Thread.currentThread().getName()+"--阻塞");
                                         queue.wait();
                                  } catch (InterruptedException e) {
                                         e.printStackTrace();
                                  }
                                  System.out.println("生产者--"+Thread.currentThread().getName()+"--被唤醒");
                           }
                     }
              }
       }
}

2、信号灯法:将上面的queue.size() <5改成信号灯flag即可;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值