线程安全
多线程访问了共享的数据,会产生线程安全问题
在下面的代码中出现了两个窗口卖同一张票,和票数出现负数的问题
加入sleep是为了提高安全问题出现的概率,不加也可,增加票数也可
package ThreadGoOn;
public class ThreadTicket implements Runnable {
private int ticketCnt = 10;
@Override
public void run() {
while (true){
if(ticketCnt>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"正在卖第"+ticketCnt+"张票");
ticketCnt--;
}/*else {
break;
}*/
}
}
}
package ThreadGoOn;
public class TestMain {
public static void main(String[] args) {
// 创建接口的实现类对象
ThreadTicket threadTicket = new ThreadTicket();
new Thread(threadTicket).start();
new Thread(threadTicket).start();
new Thread(threadTicket).start();
}
}
线程安全问题出现的原理
解决线程安全问题
方法一同步代码块
注意锁对象是同一个,所以不能将Object创建在run方法内
package ThreadDemo1127.Demo01;
/**
* @Auther hangsir
*/
public class RunnableImpl implements Runnable{
private int ticket = 100;
Object obj = new Object();
@Override
public void run() {
while (true){
synchronized (obj){
if(ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket);
ticket--;
}
}
}
}
}
package ThreadDemo1127.Demo01;
public class Main {
public static void main(String[] args) {
RunnableImpl run = new RunnableImpl();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
}
同步技术的原理
方法二同步方法
package ThreadDemo1127.Demo01;
/**
* @Auther hangsir
*/
public class RunnableImpl implements Runnable{
private int ticket = 100;
@Override
public void run() {
while (true){
sellTicket();
}
}
public synchronized void sellTicket(){
if(ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket);
ticket--;
}
}
}
方法三Lock锁
使用
package ThreadDemo1127.Demo01;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Auther hangsir
*/
public class RunnableImpl implements Runnable{
private int ticket = 100;
Lock lock = new ReentrantLock();
@Override
public void run() {
while (true){
lock.lock();
if(ticket>0){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->正在卖第"+ticket);
ticket--;
}
lock.unlock();
}
}
}
finally优化,不管程序时候出现异常,都会释放锁
线程状态
等待唤醒案例(生产者消费者模型)
代码实现
消费者线程
下面的代码加在wait后面
再加上一条华丽的分割线
生产者线程
、
将两个线程中的run方法中的内容设置成while死循环,顾客一直等着买包子。
wait带参方法和notifyAll方法
只使用notify,如果有多个线程,会随机唤醒一个消费者线程。使用notifyAll方法可以唤醒所有的消费者线程。
线程间通信
等待唤醒机制概述
分析与代码实现
代码实现
线程池
原理
好处
使用
代码实现
Runnable接口的实现类
package ThreadGoOn;
public class RunnableImpl implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"创建了一个新的线程执行!");
}
}
package ThreadGoOn;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPool {
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(2);
es.submit(new RunnableImpl());
es.submit(new RunnableImpl());
es.submit(new RunnableImpl());
es.submit(new RunnableImpl());
es.submit(new RunnableImpl());
es.shutdown();
}
}