线程安全问题
线程安全问题原因
1.多线程
2.多个线程共享数据
3.多条语句操作共享数据
线程安全问题解决
使用synchronized关键字实现同步机制
1.使用同步代码块
2.使用同步方法
锁对象:可以是任意对象
多个线程必须使用同一把锁对象,通常使用什么对象作为锁对象
非静态域中shiyongthis作为锁对象
比如:非静态同步代码块,非静态同步方法使用this
静态域中使用类的Class对象
比如:静态代码块,静态方法中使用Class对象
单例模式-懒汉式线程安全问题
public class SingletonDemo {
private static SingletonDemo instence = null;
public static SingletonDemo getInstence() {
if (instence == null) {
synchronized (SingletonDemo.class) {
if (instence == null) {
instence = new SingletonDemo();
}
}
}
return instence;
}
private SingletonDemo() {
}
}
常见线程安全的类
StringBuffer stringbuffer;
Vector vector;
Hashtable hashtable;
使用同步机制时,同步方法或同步代码块包含的代码:要尽量少,但是要包括所有操作的共享资源的代码,否则解决不了线程安全问题。包含的代码过多会影响性能。
等待唤醒机制解决经典生产者和消费者问题
/**
* @version 1.0
* @author: chutao
* 案例:有家餐馆的取餐口比较小,只能放10份快餐,厨师做完快餐放在取餐口的工作台上,
* 服务员从这个工作台取出快餐给顾客。现在有1个厨师和1个服务员。
* 等待唤醒机制解决经典生产者和消费者问题
*/
public class Demo {
public static void main(String[] args) {
//创建共享资源类
WorkBench workBench = new WorkBench();
//创建线程任务类
Waiter waiter = new Waiter(workBench);
Cooker cooker = new Cooker(workBench);
//创建线程
new Thread(waiter, "服务员").start();
new Thread(cooker, "厨师").start();
}
}
class Waiter implements Runnable {
private WorkBench workBench;
public Waiter(WorkBench workBench) {
this.workBench = workBench;
}
@Override
public void run() {
while (true) {
workBench.take();//从工作台取走
}
}
}
//线程任务类
class Cooker implements Runnable {
private WorkBench workBench;
public Cooker(WorkBench workBench) {
this.workBench = workBench;
}
@Override
public void run() {
while (true) {
workBench.put();//生产快餐,放到工作台
}
}
}
//共享资源类
class WorkBench {
private int MAX_VALUE = 10;//最大餐数
private int num;//工作台当前餐数
//往工作台放快餐的同步方法
public synchronized void put() {
if (num >= MAX_VALUE) {
try {
this.wait();//等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "----生产了" + ++num);
//唤醒等待的另一个线程:随机唤醒一个等待的线程
this.notify();
}
//从工作台取快餐的同步方法
public synchronized void take() {
if (num <= 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "----消费了" + --num);
//唤醒等待的另一个线程
this.notify();
}
}
/**
* @version 1.0
* @author: chutao
* 例:有家餐馆的取餐口比较小,只能放10份快餐,厨师做完快餐放在取餐口的工作台上,
* 服务员从这个工作台取出快餐给顾客。现在有多个厨师和多个服务员。
*/
public class Demo {
public static void main(String[] args) {
//创建共享资源类
WorkBench workBench = new WorkBench();
//创建线程任务类
Waiter waiter = new Waiter(workBench);
Cooker cooker = new Cooker(workBench);
//创建线程
new Thread(waiter, "服务员1").start();
new Thread(waiter, "服务员2").start();
new Thread(waiter, "服务员3").start();
new Thread(cooker, "厨师1").start();
new Thread(cooker, "厨师2").start();
new Thread(cooker, "厨师3").start();
}
}
class Waiter implements Runnable {
private WorkBench workBench;
public Waiter(WorkBench workBench) {
this.workBench = workBench;
}
@Override
public void run() {
while (true) {
workBench.take();//从工作台取走
}
}
}
//线程任务类
class Cooker implements Runnable {
private WorkBench workBench;
public Cooker(WorkBench workBench) {
this.workBench = workBench;
}
@Override
public void run() {
while (true) {
workBench.put();//生产快餐,放到工作台
}
}
}
//共享资源类
class WorkBench {
private int MAX_VALUE = 10;//最大餐数
private int num;//工作台当前餐数
//往工作台放快餐的同步方法
public synchronized void put() {
while (num >= MAX_VALUE) {
try {
this.wait();//等待,wait方法会释放锁对象
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "----生产了" + ++num);
//唤醒等待的全部线程
this.notifyAll();
}
//从工作台取快餐的同步方法
public synchronized void take() {
while (num <= 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "----消费了" + --num);
//唤醒等待的全部线程
this.notifyAll();
}
}