Java多线程——安全与死锁问题

一、实现多线程的方式:

方式一:继承Thread类     
    
    
  a.自定义类继承Thread类

    
    
    
  b.在自定义类中重写run()方法

    
    
    
  c.创建自定义类的对象

    
    
    
  d.启动线程的对象


方式二:实现Runnable接口(大多数使用)     
    
    
  a.自定义类实现Runnable接口

    
    
      b.在自定义类中重写run()方法

    
    
    
  c.创建自定义类的对象

    
    
    
  d.创建Thread类的对象,并把c步骤创建的对象作为构造参数传递

    
    
    
  优点:避免由于单继承带来的局限性

    
    
    
    
    
    适合多个程序的代码处理同一个资源的情况,把线程同程序的代码、数据有效分离,较好的体现了面向对象的设计思想。



public class SellTicket implements Runnable {
private int tickets = 100;

public void run() {
while(true) {
if(tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在出售第"+(tickets--)+"张票");
  }
}    
}
}
 

public class SellTicketDemo {
public static void main(String[] args) {
SellTicket st = new SellTicket();
Thread t1 = new Thread(st,"窗口1");
Thread t2 = new Thread(st,"窗口2");
Thread t3 = new Thread(st,"窗口3");

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

出现多线程安全问题的原因:     
    
    1.是否是多线程环境

    
    
    2.是否共享数据

    
    
    3.是否有多条语句操作共享数据


二、解决线程安全问题——
      方式一、同步代码块     
    
    同步机制:把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能来执行


       格式:synchronized(对象) {需要同步的代码;}
   
    
    
 同步可以解决安全问题的根本原因就在这个对象上。该对象如同锁的功能。多个线程,需要共同拥有一个对象     
    
    用法
    
    
    
    
    
在run()方法外创建一个对象 Object obj = new Object(); 对象是任意创建的     
    
    
  
    
  …….  
    
                        while(true)  {

 
    
    
    
    
    
    
    
   synchronized(obj)  {      //相当于一把锁,t1抢到CPU执行权后就锁上了               
    
    
    
    
    
    
    
    
    if(tickets > 0)  { 

    
    
    
    
    .
……      //t1睡眠时t2,t3也会抢CPU执行权,但由于锁上进不去。当t1执行完后 t1,t2,t3还会再次抢CPU执行权

    
      同步的特点:多个线程使用的是同一个锁对象

    
      同步的弊端:当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。

    
    同步方法的格式以及锁对象问题

    
    
    
  直接将synchronized加到方法上

    
    
    
    private synchronized void 方法名() {…}  

    
    
    
    run()方法中直接调用 但是需要注意锁对象的问题 


        同步方法的锁对象是this
        静态方法的锁对象是类的字节码文件对象 即当前类名.class (静态方法是随着类的加载而加载)

  
      方式二、Lock锁的使用(Lock属于接口)

    
    
    
    1.明确看到在哪加锁,在哪释放锁

    
    
    
    2.方法:void lock();获取锁  void unlock();释放锁

    
    
    
    3.ReentrantLock是Lock的实现类。

    
    
    
  用法: 
    
    
    
    
    
   
在自定义类中定义锁对象 如:private Lock lock = new ReentrantLock();     
    
    
    
  …….  
    


                        while(true)  {                           
    
    
    
    
    
    
    try {                           //加入try是为了防止里面的走错,这样可以直接释放
    
    
    
    
    
    
    
    
    
   lock.lock();


                                       if…     
    
    
    
    
    
    
    }finally {

    
    
    
    
    
    
    
    
     lock.unlock();


                                }…
三、死锁问题     
    
    是指两个或两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待的现象

    
    
    同步弊端:效率低
    
    
    
    
    
    
    
 
如果出现同步嵌套就容易产生死锁问题     
    
    出现死锁问题例子:

public class MyLock {
//定义两个锁对象
public static final Object objA = new Object();
public static final Object objB = new Object();
}
public class DieLock extends Thread {
public boolean flag;
public DieLock(boolean flag) {
this.flag = flag;
}
 
public void run() {
if(flag) {
synchronized(MyLock.objA) {
System.out.rpintln("if objA");
synchronized(MyLock.objB) {
System.out.rpintln("else objA");
}
}
}else {
synchronized(MyLock.objB) {
System.out.rpintln("else objB");
synchronized(MyLock.objA) {
System.out.rpintln("else objA");
    }
}
}
}
}
public class Demo {
public static void main(String[] args) {
DieLock d1 = new DieLock(true);
DieLock d2 = new DieLock(false);

d1.start();
d2.start();
}
}     有两把锁objA、objB,两个线程d1、d2, d1为true会进入第一部分代码块,d2进入第二部分代码块,理想状态下,d1和d2正常交叉走完代码块,但是由于两个线程抢CPU的执行权时,有可能出现d1走完第一部分的第一个锁后进入下一个锁时,d2在第二部分代码块还没有执行完第一个锁,所以会等待d2完成,然后两个线程进入不到对方的代码块中以至于互相等待,因此出现死锁现象。
四、线程通信     
      不同种类的线程针对同一个资源的操作。


      若想共享数据源,可以在外界把这个数据源对象创建出来,通过构造方法传递给其他的类。


持续更新~

    原文作者:java锁
    原文地址: https://blog.csdn.net/AntaoMen/article/details/51702628
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞