本文已参与「新人创作礼」活动,一起开启掘金创作之路。
方式二:同步方法
class TicketImpl implements Runnable {
private int ticket = 100;
@Override
public void run() {
while (true) {
payTicket();
}
}
public synchronized void payTicket() {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "- 第" + ticket + "张");
try {
Thread.sleep(100);// 提高线程安全问题出现的频率,设置睡眠
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket--;
}
}
}
# 注意:同步方法的锁对象是实现类的对象(this)
# 第二种方法:将同步锁改用this
public void payTicket() {
synchronized (this) {
if (ticket > 0) {
System.out.println(Thread.currentThread().getName() + "- 第" + ticket + "张");
try {
Thread.sleep(100);// 提高线程安全问题出现的频率,设置睡眠
} catch (InterruptedException e) {
e.printStackTrace();
}
ticket--;
}
}
}
方式三:锁机制
public class Demo04lock {
public static void main(String[] args) {
Ticketimpl runnable = new Ticketimpl();
Thread thread1 = new Thread(runnable, "窗口1");
Thread thread2 = new Thread(runnable, "窗口2");
Thread thread3 = new Thread(runnable, "窗口3");
thread1.start();
thread2.start();
thread3.start();
}
}
class Ticketimpl implements Runnable {
private static int ticket = 100;
// 1. 在成员位置创建ReentrantLock对象
Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
payTicket();
}
}
void payTicket() {
// 2. 在可能会出现线程安全的代码前调用Lock接口中的方法lock获取锁
lock.lock();
if (ticket > 0) {
try {
System.out.println(Thread.currentThread().getName() + "- 第" + ticket + "张");
Thread.sleep(100);
ticket--;
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 3. 在可能会出现线程安全的代码后调用Lock接口中的方法unlock释放锁
lock.unlock();
}
}
}
}
线程间的通信 ( 生产者与消费者问题 )
多个线程并发执行时, 在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们希望他们有规律的执行, 那么多线程之间需要一些协调通信,以此来帮我们达到多线程共同操作一份数据。
wait/notify 就是线程间的一种协作机制。
线程池
如果并发的线程数量很多,且每个线程都执行一个时间很短的任务就结束了,这样频繁创建、销毁线程就会大大降低 系统的效率。
好处
- 降低资源消耗。
- 提高响应速度。
- 提高线程的可管理性。可以根据系统的承受能力,调整线程池中工作线线程的数目。
创建线程池的方法:
- 固定大小的线程池:newFixedThreadPool
- 单线程池:singleThreadExecutor
- 缓存线程池:CachedThreadPool
- 定长周期性调度的线程池:schedulThreadPool