69期-Java SE-014_多线程-3-001-002

### 死锁

死锁是一种错误,实际开发中需要注意避免这种错误的出现。

```java
public class Chopsticks {

}
```

```java
public class DeadLockRunnable implements Runnable {
    public int num;
    private static Chopsticks chopsticks1 = new Chopsticks();
    private static Chopsticks chopsticks2 = new Chopsticks();

    @Override
    public void run() {
        // TODO Auto-generated method stub
        if(num == 1) {
            System.out.println(Thread.currentThread().getName()+"获取到chopsticks1,等待获取chopsticks2");
            synchronized (chopsticks1) {
                try {
                    Thread.currentThread().sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                synchronized (chopsticks2) {
                    System.out.println(Thread.currentThread().getName()+"用餐完毕");
                }
            }
        }
        
        if(num == 2) {
            System.out.println(Thread.currentThread().getName()+"获取到chopsticks2,等待获取chopsticks1");
            synchronized (chopsticks2) {
                try {
                    Thread.currentThread().sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                synchronized (chopsticks1) {
                    System.out.println(Thread.currentThread().getName()+"用餐完毕");
                }
            }
        }
        
    }

}
```

```java

public class Test {
    public static void main(String[] args) {
        DeadLockRunnable deadLockRunnable1 = new DeadLockRunnable();
        deadLockRunnable1.num=1;
        DeadLockRunnable deadLockRunnable2 = new DeadLockRunnable();
        deadLockRunnable2.num=2;
        Thread thread = new Thread(deadLockRunnable1,"张三");
        Thread thread2 = new Thread(deadLockRunnable2,"李四");
        thread.start();
        try {
            Thread.currentThread().sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        thread2.start();
    }
}
```

### 重入锁

重入锁是实现线程同步的另外一种方式,可以看作是synchronized的升级,synchronized是通过JVM实现的,重入锁是通过JDK实现的。

重入锁的特点:

可以给同一个资源添加多个锁,同时解锁的方式与synchronized也有不同,synchronized的锁是线程执行完毕之后自动释放,重入锁必须手动释放。

可中断是指某个线程在等待获取锁的过程中可以主动终止线程,通过调用 lockInterruptibly() 方法来实现。

重入锁还具备限时性的特点,指可以判断某个线程在一定的时间内能否获取锁,通过调用tryLock(long timeout,TimeUnit unit)方法来实现,其中timeout指时间数值,unit指时间单位,返回值是boolean,true 表示在该时间段内可以获取锁,false表示在该时间段内没有获取锁。

### 生产者消费者模式

在一个生产环境中,生产者和消费者在同一个时间段内共享同一块缓冲区,生产者负责向缓冲区中添加数据,消费者负责从缓冲区中取出数据,以生产汉堡和消费汉堡为例来实现生产者消费者模式。

```java
public class Hamburger {
    private int id;

    public int getId() {
        return id;
    }

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

    @Override
    public String toString() {
        return "Hamburger [id=" + id + "]";
    }
    
    public Hamburger(int id) {
        this.id = id;
    }
}
```

```java
public class Container {
    public Hamburger[] array = new Hamburger[6];
    public int index = 0;
    //向容器中添加汉堡
    public synchronized void push(Hamburger hamburger) {
        while(index == array.length) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        this.notify();
        array[index] = hamburger;
        index++;
        System.out.println("生产了一个汉堡:"+hamburger);
    }
    //从容器中取出汉堡
    public synchronized Hamburger pop() {
        while(index == 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        this.notify();
        index--;
        System.out.println("消费了一个汉堡"+array[index]);
        return array[index];
    }
}
```

```java
public class Producer implements Runnable {
    private Container container = null;
    public Producer(Container container) {
        this.container = container;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i = 0; i < 30; i++) {
            Hamburger hamburger = new Hamburger(i);
            this.container.push(hamburger);
            try {
                Thread.currentThread().sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
```

```java
public class Consumer implements Runnable {
    private Container container = null;
    
    public Consumer(Container container) {
        this.container = container;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i = 0; i < 30; i++) {
            this.container.pop();
            try {
                Thread.currentThread().sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
```

```java
public class Test5 {
    public static void main(String[] args) {
        Container container = new Container();
        Producer producer = new Producer(container);
        Consumer consumer = new Consumer(container);
        new Thread(producer).start();
        new Thread(producer).start();
        new Thread(consumer).start();
        new Thread(consumer).start();
        new Thread(consumer).start();
    }
}
```

### 练习

火车站共有3个窗口出售火车票,共15张票,用多线程模拟3个窗口的售票情况。

```java

public class TicketRunnable implements Runnable {
    //剩余的火车票
    public int scount = 15;
    //已售出的火车票
    public int ocount = 0;

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(scount>0) {
            try {
                Thread.currentThread().sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if(scount == 0) {
                return;
            }
            synchronized (TicketRunnable.class) {
                scount--;
                ocount++;
                if(scount == 0) {
                    System.out.println(Thread.currentThread().getName()+"售出了第"+ocount+"张火车票,火车票已售完");
                }else {
                    System.out.println(Thread.currentThread().getName()+"售出了第"+ocount+"张火车票,剩余"+scount+"张火车票");
                }
            }
        }
    }
    
}
```

```java
public class Test6 {
    public static void main(String[] args) {
        TicketRunnable ticketRunnable = new TicketRunnable();
        new Thread(ticketRunnable,"窗口1").start();
        new Thread(ticketRunnable,"窗口2").start();
        new Thread(ticketRunnable,"窗口3").start();
    }
}
```



### 集合框架

集合可以理解为是一个长度可以改变,可以存放任意数据类型的动态数组。

Collection            集合框架最基本的接口,存储一组无序、不唯一的对象

List                    Collection的子接口,存储一组无序、不唯一的对象

Set                    Collection的子接口,存储一组无序、唯一的对象

Map                独立于Collection的另外一个接口,存储一组键值对象,提供键到值的映射

Iterator                输出集合元素的接口,一般适用于无序集合,从前向后单向输出

ListIterator            Iterator的子接口,可以双向输出集合中的元素

Eummeration        传统的输出接口,已经被Irerator所取代

Account.java

import java.util.concurrent.locks.ReentrantLock;

public class Account implements Runnable {
    private static int num;
    private ReentrantLock reentrantLock = new ReentrantLock();
    @Override
    public void run() {
        // TODO Auto-generated method stub
        reentrantLock.lock();
        reentrantLock.lock();
        num++;
        System.out.println(Thread.currentThread().getName()+"是当前的第"+num+"位访问");
        reentrantLock.unlock();
        reentrantLock.unlock();
    }

}

Chopsticks.java

public class Chopsticks {

}

Consumer.java

public class Consumer implements Runnable {
    private Container container = null;
    
    public Consumer(Container container) {
        this.container = container;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i = 0; i < 30; i++) {
            this.container.pop();
            try {
                Thread.currentThread().sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}

Container.java

public class Container {
    public Hamburger[] array = new Hamburger[6];
    public int index = 0;
    //向容器中添加汉堡
    public synchronized void push(Hamburger hamburger) {
        while(index == array.length) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        this.notify();
        array[index] = hamburger;
        index++;
        System.out.println("生产了一个汉堡:"+hamburger);
    }
    //从容器中取出汉堡
    public synchronized Hamburger pop() {
        while(index == 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        this.notify();
        index--;
        System.out.println("消费了一个汉堡"+array[index]);
        return array[index];
    }
}

DeadLockRunnable.java

public class DeadLockRunnable implements Runnable {
    
    public int num;
    private static Chopsticks chopsticks1 = new Chopsticks();
    private static Chopsticks chopsticks2 = new Chopsticks();

    @Override
    public void run() {
        // TODO Auto-generated method stub
        if(num == 1) {
            System.out.println(Thread.currentThread().getName()+"获取到chopsticks1,等待获取chopsticks2");
            synchronized (chopsticks1) {
                try {
                    Thread.currentThread().sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                synchronized (chopsticks2) {
                    System.out.println(Thread.currentThread().getName()+"用餐完毕");
                }
            }
        }
        
        if(num == 2) {
            System.out.println(Thread.currentThread().getName()+"获取到chopsticks2,等待获取chopsticks1");
            synchronized (chopsticks2) {
                try {
                    Thread.currentThread().sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                synchronized (chopsticks1) {
                    System.out.println(Thread.currentThread().getName()+"用餐完毕");
                }
            }
        }
        
    }

}

Hamburger.java

public class Hamburger {
    private int id;

    public int getId() {
        return id;
    }

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

    @Override
    public String toString() {
        return "Hamburger [id=" + id + "]";
    }
    
    public Hamburger(int id) {
        this.id = id;
    }
}

Producer.java

public class Producer implements Runnable {
    private Container container = null;
    public Producer(Container container) {
        this.container = container;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        for(int i = 0; i < 30; i++) {
            Hamburger hamburger = new Hamburger(i);
            this.container.push(hamburger);
            try {
                Thread.currentThread().sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}

StopLock.java

import java.util.concurrent.locks.ReentrantLock;

public class StopLock implements Runnable{
    
    private ReentrantLock reentrantLock = new ReentrantLock();

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            reentrantLock.lockInterruptibly();
            System.out.println(Thread.currentThread().getName()+"get lock");
            Thread.currentThread().sleep(5000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally {
            reentrantLock.unlock();
        }
    }

}

Test.java

public class Test {
    public static void main(String[] args) {
        DeadLockRunnable deadLockRunnable1 = new DeadLockRunnable();
        deadLockRunnable1.num=1;
        DeadLockRunnable deadLockRunnable2 = new DeadLockRunnable();
        deadLockRunnable2.num=2;
        Thread thread = new Thread(deadLockRunnable1,"张三");
        Thread thread2 = new Thread(deadLockRunnable2,"李四");
        thread.start();
        try {
            Thread.currentThread().sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        thread2.start();
    }
}

Test2.java

public class Test2 {
    public static void main(String[] args) {
        Account account = new Account();
        Thread thread1 = new Thread(account,"用户A");
        Thread thread2 = new Thread(account,"用户B");
        thread1.start();
        thread2.start();
    }
}

Test3.java

public class Test3 {
    public static void main(String[] args) {
        StopLock stopLock = new StopLock();
        Thread thread1 = new Thread(stopLock,"线程1");
        Thread thread2 = new Thread(stopLock,"线程2");
        thread1.start();
        thread2.start();
        try {
            Thread.currentThread().sleep(1000);
            thread2.interrupt();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

Test4.java

public class Test4 {
    public static void main(String[] args) {
        TimeLock timeLock = new TimeLock();
        new Thread(timeLock,"线程1").start();
        new Thread(timeLock,"线程2").start();
    }
}

Test5.java

public class Test5 {
    public static void main(String[] args) {
        Container container = new Container();
        Producer producer = new Producer(container);
        Consumer consumer = new Consumer(container);
        new Thread(producer).start();
        new Thread(producer).start();
        new Thread(consumer).start();
        new Thread(consumer).start();
        new Thread(consumer).start();
    }
}

Test6.java

public class Test6 {
    public static void main(String[] args) {
        TicketRunnable ticketRunnable = new TicketRunnable();
        new Thread(ticketRunnable,"窗口1").start();
        new Thread(ticketRunnable,"窗口2").start();
        new Thread(ticketRunnable,"窗口3").start();
    }
}

TickerRunnable.java

public class TicketRunnable implements Runnable {
    //剩余的火车票
    public int scount = 15;
    //已售出的火车票
    public int ocount = 0;

    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(scount>0) {
            try {
                Thread.currentThread().sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if(scount == 0) {
                return;
            }
            synchronized (TicketRunnable.class) {
                scount--;
                ocount++;
                if(scount == 0) {
                    System.out.println(Thread.currentThread().getName()+"售出了第"+ocount+"张火车票,火车票已售完");
                }else {
                    System.out.println(Thread.currentThread().getName()+"售出了第"+ocount+"张火车票,剩余"+scount+"张火车票");
                }
            }
        }
    }
    
}

TimeLock.java

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

public class TimeLock implements Runnable {
    public ReentrantLock reentrantLock = new ReentrantLock();
    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            if(reentrantLock.tryLock(6, TimeUnit.SECONDS)) {
                System.out.println(Thread.currentThread().getName()+"get lock");
                Thread.currentThread().sleep(5000);
            }else {
                System.out.println(Thread.currentThread().getName()+"not lock");
            }
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if(reentrantLock.isHeldByCurrentThread()) {
                reentrantLock.unlock();
            }
        }
    }

}
原文地址:https://www.cnblogs.com/HiJackykun/p/11172903.html